tcuTexture.js (145714B)
1 /*------------------------------------------------------------------------- 2 * drawElements Quality Program OpenGL ES Utilities 3 * ------------------------------------------------ 4 * 5 * Copyright 2014 The Android Open Source Project 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 * 19 */ 20 21 'use strict'; 22 goog.provide('framework.common.tcuTexture'); 23 goog.require('framework.common.tcuFloat'); 24 goog.require('framework.delibs.debase.deMath'); 25 goog.require('framework.delibs.debase.deString'); 26 goog.require('framework.delibs.debase.deUtil'); 27 28 goog.scope(function() { 29 30 var tcuTexture = framework.common.tcuTexture; 31 var deMath = framework.delibs.debase.deMath; 32 var tcuFloat = framework.common.tcuFloat; 33 var deString = framework.delibs.debase.deString; 34 var deUtil = framework.delibs.debase.deUtil; 35 36 var DE_ASSERT = function(x) { 37 if (!x) 38 throw new Error('Assert failed'); 39 }; 40 41 /** 42 * Texture tcuTexture.channel order 43 * @enum 44 */ 45 tcuTexture.ChannelOrder = { 46 R: 0, 47 A: 1, 48 I: 2, 49 L: 3, 50 LA: 4, 51 RG: 5, 52 RA: 6, 53 RGB: 7, 54 RGBA: 8, 55 ARGB: 9, 56 BGRA: 10, 57 58 sRGB: 11, 59 sRGBA: 12, 60 61 D: 13, 62 S: 14, 63 DS: 15 64 }; 65 66 /** 67 * Texture tcuTexture.channel type 68 * @enum 69 */ 70 tcuTexture.ChannelType = { 71 SNORM_INT8: 0, 72 SNORM_INT16: 1, 73 SNORM_INT32: 2, 74 UNORM_INT8: 3, 75 UNORM_INT16: 4, 76 UNORM_INT32: 5, 77 UNORM_SHORT_565: 6, 78 UNORM_SHORT_555: 7, 79 UNORM_SHORT_4444: 8, 80 UNORM_SHORT_5551: 9, 81 UNORM_INT_101010: 10, 82 UNORM_INT_1010102_REV: 11, 83 UNSIGNED_INT_1010102_REV: 12, 84 UNSIGNED_INT_11F_11F_10F_REV: 13, 85 UNSIGNED_INT_999_E5_REV: 14, 86 UNSIGNED_INT_24_8: 15, 87 SIGNED_INT8: 16, 88 SIGNED_INT16: 17, 89 SIGNED_INT32: 18, 90 UNSIGNED_INT8: 19, 91 UNSIGNED_INT16: 20, 92 UNSIGNED_INT32: 21, 93 HALF_FLOAT: 22, 94 FLOAT: 23, 95 FLOAT_UNSIGNED_INT_24_8_REV: 24 96 }; 97 98 /** 99 * Enums for tcuTexture.TextureChannelClass 100 * @enum {number} 101 */ 102 tcuTexture.TextureChannelClass = { 103 104 SIGNED_FIXED_POINT: 0, 105 UNSIGNED_FIXED_POINT: 1, 106 SIGNED_INTEGER: 2, 107 UNSIGNED_INTEGER: 3, 108 FLOATING_POINT: 4 109 }; 110 111 /** 112 * @param {?tcuTexture.ChannelType} channelType 113 * @return {tcuTexture.TextureChannelClass} 114 */ 115 tcuTexture.getTextureChannelClass = function(channelType) { 116 117 switch (channelType) { 118 case tcuTexture.ChannelType.SNORM_INT8: return tcuTexture.TextureChannelClass.SIGNED_FIXED_POINT; 119 case tcuTexture.ChannelType.SNORM_INT16: return tcuTexture.TextureChannelClass.SIGNED_FIXED_POINT; 120 case tcuTexture.ChannelType.UNORM_INT8: return tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT; 121 case tcuTexture.ChannelType.UNORM_INT16: return tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT; 122 case tcuTexture.ChannelType.UNORM_SHORT_565: return tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT; 123 case tcuTexture.ChannelType.UNORM_SHORT_555: return tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT; 124 case tcuTexture.ChannelType.UNORM_SHORT_4444: return tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT; 125 case tcuTexture.ChannelType.UNORM_SHORT_5551: return tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT; 126 case tcuTexture.ChannelType.UNORM_INT_101010: return tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT; 127 case tcuTexture.ChannelType.UNORM_INT_1010102_REV: return tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT; 128 case tcuTexture.ChannelType.UNSIGNED_INT_1010102_REV: return tcuTexture.TextureChannelClass.UNSIGNED_INTEGER; 129 case tcuTexture.ChannelType.UNSIGNED_INT_11F_11F_10F_REV: return tcuTexture.TextureChannelClass.FLOATING_POINT; 130 case tcuTexture.ChannelType.UNSIGNED_INT_999_E5_REV: return tcuTexture.TextureChannelClass.FLOATING_POINT; 131 case tcuTexture.ChannelType.SIGNED_INT8: return tcuTexture.TextureChannelClass.SIGNED_INTEGER; 132 case tcuTexture.ChannelType.SIGNED_INT16: return tcuTexture.TextureChannelClass.SIGNED_INTEGER; 133 case tcuTexture.ChannelType.SIGNED_INT32: return tcuTexture.TextureChannelClass.SIGNED_INTEGER; 134 case tcuTexture.ChannelType.UNSIGNED_INT8: return tcuTexture.TextureChannelClass.UNSIGNED_INTEGER; 135 case tcuTexture.ChannelType.UNSIGNED_INT16: return tcuTexture.TextureChannelClass.UNSIGNED_INTEGER; 136 case tcuTexture.ChannelType.UNSIGNED_INT32: return tcuTexture.TextureChannelClass.UNSIGNED_INTEGER; 137 case tcuTexture.ChannelType.HALF_FLOAT: return tcuTexture.TextureChannelClass.FLOATING_POINT; 138 case tcuTexture.ChannelType.FLOAT: return tcuTexture.TextureChannelClass.FLOATING_POINT; 139 default: return /** @type {tcuTexture.TextureChannelClass<number>} */ (Object.keys(tcuTexture.ChannelType).length); 140 } 141 }; 142 143 /** 144 * @param {tcuTexture.TextureFormat} format 145 */ 146 tcuTexture.isFixedPointDepthTextureFormat = function(format) { 147 var channelClass = tcuTexture.getTextureChannelClass(format.type); 148 149 if (format.order == tcuTexture.ChannelOrder.D) { 150 // depth internal formats cannot be non-normalized integers 151 return channelClass != tcuTexture.TextureChannelClass.FLOATING_POINT; 152 } else if (format.order == tcuTexture.ChannelOrder.DS) { 153 // combined formats have no single channel class, detect format manually 154 switch (format.type) { 155 case tcuTexture.ChannelType.FLOAT_UNSIGNED_INT_24_8_REV: return false; 156 case tcuTexture.ChannelType.UNSIGNED_INT_24_8: return true; 157 158 default: 159 // unknown format 160 DE_ASSERT(false); 161 return true; 162 } 163 } 164 return false; 165 }; 166 167 /** 168 * @param {Array<number>} color 169 * @param {tcuTexture.CompareMode} compare 170 * @param {number} chanNdx 171 * @param {number} ref_ 172 * @param {boolean} isFixedPoint 173 */ 174 tcuTexture.execCompare = function(color, compare, chanNdx, ref_, isFixedPoint) { 175 var clampValues = isFixedPoint; 176 var cmp = clampValues ? deMath.clamp(color[chanNdx], 0.0, 1.0) : color[chanNdx]; 177 var ref = clampValues ? deMath.clamp(ref_, 0.0, 1.0) : ref_; 178 var res = false; 179 180 switch (compare) { 181 case tcuTexture.CompareMode.COMPAREMODE_LESS: res = ref < cmp; break; 182 case tcuTexture.CompareMode.COMPAREMODE_LESS_OR_EQUAL: res = ref <= cmp; break; 183 case tcuTexture.CompareMode.COMPAREMODE_GREATER: res = ref > cmp; break; 184 case tcuTexture.CompareMode.COMPAREMODE_GREATER_OR_EQUAL: res = ref >= cmp; break; 185 case tcuTexture.CompareMode.COMPAREMODE_EQUAL: res = ref == cmp; break; 186 case tcuTexture.CompareMode.COMPAREMODE_NOT_EQUAL: res = ref != cmp; break; 187 case tcuTexture.CompareMode.COMPAREMODE_ALWAYS: res = true; break; 188 case tcuTexture.CompareMode.COMPAREMODE_NEVER: res = false; break; 189 default: 190 DE_ASSERT(false); 191 } 192 193 return res ? 1.0 : 0.0; 194 }; 195 196 /** 197 * @param {Array<tcuTexture.ConstPixelBufferAccess>} levels 198 * @param {number} numLevels 199 * @param {tcuTexture.Sampler} sampler 200 * @param {number} ref 201 * @param {number} s 202 * @param {number} t 203 * @param {number} lod 204 * @param {Array<number>} offset 205 */ 206 tcuTexture.sampleLevelArray2DCompare = function(levels, numLevels, sampler, ref, s, t, lod, offset) { 207 var magnified = lod <= sampler.lodThreshold; 208 var filterMode = magnified ? sampler.magFilter : sampler.minFilter; 209 210 switch (filterMode) { 211 case tcuTexture.FilterMode.NEAREST: return levels[0].sample2DCompare(sampler, filterMode, ref, s, t, offset); 212 case tcuTexture.FilterMode.LINEAR: return levels[0].sample2DCompare(sampler, filterMode, ref, s, t, offset); 213 214 case tcuTexture.FilterMode.NEAREST_MIPMAP_NEAREST: 215 case tcuTexture.FilterMode.LINEAR_MIPMAP_NEAREST: { 216 var maxLevel = numLevels - 1; 217 var level = deMath.clamp(Math.ceil(lod + 0.5) - 1, 0, maxLevel); 218 var levelFilter = filterMode == tcuTexture.FilterMode.LINEAR_MIPMAP_NEAREST ? tcuTexture.FilterMode.LINEAR : tcuTexture.FilterMode.NEAREST; 219 220 return levels[level].sample2DCompare(sampler, levelFilter, ref, s, t, offset); 221 } 222 223 case tcuTexture.FilterMode.NEAREST_MIPMAP_LINEAR: 224 case tcuTexture.FilterMode.LINEAR_MIPMAP_LINEAR: { 225 var maxLevel = numLevels - 1; 226 var level0 = deMath.clamp(Math.floor(lod), 0, maxLevel); 227 var level1 = Math.min(maxLevel, level0 + 1); 228 var levelFilter = filterMode == tcuTexture.FilterMode.LINEAR_MIPMAP_LINEAR ? tcuTexture.FilterMode.LINEAR : tcuTexture.FilterMode.NEAREST; 229 var f = deMath.deFloatFrac(lod); 230 var t0 = levels[level0].sample2DCompare(sampler, levelFilter, ref, s, t, offset); 231 var t1 = levels[level1].sample2DCompare(sampler, levelFilter, ref, s, t, offset); 232 233 return t0 * (1.0 - f) + t1 * f; 234 } 235 236 default: 237 DE_ASSERT(false); 238 return 0.0; 239 } 240 }; 241 242 /** 243 * @param {tcuTexture.ConstPixelBufferAccess} access 244 * @param {tcuTexture.Sampler} sampler 245 * @param {number} ref 246 * @param {number} u 247 * @param {number} v 248 * @param {Array<number>} offset 249 * @param {boolean} isFixedPointDepthFormat 250 * @return {number} 251 */ 252 tcuTexture.sampleLinear2DCompare = function(access, sampler, ref, u, v, offset, isFixedPointDepthFormat) { 253 var w = access.getWidth(); 254 var h = access.getHeight(); 255 256 var x0 = Math.floor(u - 0.5) + offset[0]; 257 var x1 = x0 + 1; 258 var y0 = Math.floor(v - 0.5) + offset[1]; 259 var y1 = y0 + 1; 260 261 var i0 = tcuTexture.wrap(sampler.wrapS, x0, w); 262 var i1 = tcuTexture.wrap(sampler.wrapS, x1, w); 263 var j0 = tcuTexture.wrap(sampler.wrapT, y0, h); 264 var j1 = tcuTexture.wrap(sampler.wrapT, y1, h); 265 266 var a = deMath.deFloatFrac(u - 0.5); 267 var b = deMath.deFloatFrac(v - 0.5); 268 269 var i0UseBorder = sampler.wrapS == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(i0, 0, w); 270 var i1UseBorder = sampler.wrapS == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(i1, 0, w); 271 var j0UseBorder = sampler.wrapT == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(j0, 0, h); 272 var j1UseBorder = sampler.wrapT == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(j1, 0, h); 273 274 // Border color for out-of-range coordinates if using CLAMP_TO_BORDER, otherwise execute lookups. 275 var p00Clr = (i0UseBorder || j0UseBorder) ? sampler.borderColor : tcuTexture.lookup(access, i0, j0, offset[2]); 276 var p10Clr = (i1UseBorder || j0UseBorder) ? sampler.borderColor : tcuTexture.lookup(access, i1, j0, offset[2]); 277 var p01Clr = (i0UseBorder || j1UseBorder) ? sampler.borderColor : tcuTexture.lookup(access, i0, j1, offset[2]); 278 var p11Clr = (i1UseBorder || j1UseBorder) ? sampler.borderColor : tcuTexture.lookup(access, i1, j1, offset[2]); 279 280 // Execute comparisons. 281 var p00 = tcuTexture.execCompare(p00Clr, sampler.compare, sampler.compareChannel, ref, isFixedPointDepthFormat); 282 var p10 = tcuTexture.execCompare(p10Clr, sampler.compare, sampler.compareChannel, ref, isFixedPointDepthFormat); 283 var p01 = tcuTexture.execCompare(p01Clr, sampler.compare, sampler.compareChannel, ref, isFixedPointDepthFormat); 284 var p11 = tcuTexture.execCompare(p11Clr, sampler.compare, sampler.compareChannel, ref, isFixedPointDepthFormat); 285 286 // Interpolate. 287 return (p00 * (1.0 - a) * (1.0 - b)) + 288 (p10 * (a) * (1.0 - b)) + 289 (p01 * (1.0 - a) * (b)) + 290 (p11 * (a) * (b)); 291 }; 292 293 /** 294 * Construct texture format 295 * @param {?tcuTexture.ChannelOrder} order 296 * @param {?tcuTexture.ChannelType} type 297 * 298 * @constructor 299 */ 300 tcuTexture.TextureFormat = function(order, type) { 301 this.order = order; 302 this.type = type; 303 }; 304 305 /** 306 * Compare two formats 307 * @param {tcuTexture.TextureFormat} format Format to compare with 308 * @return {boolean} 309 */ 310 tcuTexture.TextureFormat.prototype.isEqual = function(format) { 311 return this.order === format.order && this.type === format.type; 312 }; 313 314 tcuTexture.TextureFormat.prototype.toString = function() { 315 return 'TextureFormat(' + deString.enumToString(tcuTexture.ChannelOrder, this.order) + ', ' + 316 deString.enumToString(tcuTexture.ChannelType, this.type) + ')'; 317 }; 318 319 /** 320 * Is format sRGB? 321 * @return {boolean} 322 */ 323 tcuTexture.TextureFormat.prototype.isSRGB = function() { 324 return this.order === tcuTexture.ChannelOrder.sRGB || this.order === tcuTexture.ChannelOrder.sRGBA; 325 }; 326 327 tcuTexture.TextureFormat.prototype.getNumStencilBits = function() { 328 switch (this.order) { 329 case tcuTexture.ChannelOrder.S: 330 switch (this.type) { 331 case tcuTexture.ChannelType.UNSIGNED_INT8: return 8; 332 case tcuTexture.ChannelType.UNSIGNED_INT16: return 16; 333 case tcuTexture.ChannelType.UNSIGNED_INT32: return 32; 334 default: 335 throw new Error('Wrong type: ' + this.type); 336 } 337 338 case tcuTexture.ChannelOrder.DS: 339 switch (this.type) { 340 case tcuTexture.ChannelType.UNSIGNED_INT_24_8: return 8; 341 case tcuTexture.ChannelType.FLOAT_UNSIGNED_INT_24_8_REV: return 8; 342 default: 343 throw new Error('Wrong type: ' + this.type); 344 } 345 346 default: 347 throw new Error('Wrong order: ' + this.order); 348 } 349 }; 350 351 /** 352 * Get TypedArray type that can be used to access texture. 353 * @param {?tcuTexture.ChannelType} type 354 * @return TypedArray that supports the tcuTexture.channel type. 355 */ 356 tcuTexture.getTypedArray = function(type) { 357 switch (type) { 358 case tcuTexture.ChannelType.SNORM_INT8: return Int8Array; 359 case tcuTexture.ChannelType.SNORM_INT16: return Int16Array; 360 case tcuTexture.ChannelType.SNORM_INT32: return Int32Array; 361 case tcuTexture.ChannelType.UNORM_INT8: return Uint8Array; 362 case tcuTexture.ChannelType.UNORM_INT16: return Uint16Array; 363 case tcuTexture.ChannelType.UNORM_INT32: return Uint32Array; 364 case tcuTexture.ChannelType.UNORM_SHORT_565: return Uint16Array; 365 case tcuTexture.ChannelType.UNORM_SHORT_555: return Uint16Array; 366 case tcuTexture.ChannelType.UNORM_SHORT_4444: return Uint16Array; 367 case tcuTexture.ChannelType.UNORM_SHORT_5551: return Uint16Array; 368 case tcuTexture.ChannelType.UNORM_INT_101010: return Uint32Array; 369 case tcuTexture.ChannelType.UNORM_INT_1010102_REV: return Uint32Array; 370 case tcuTexture.ChannelType.UNSIGNED_INT_1010102_REV: return Uint32Array; 371 case tcuTexture.ChannelType.UNSIGNED_INT_11F_11F_10F_REV: return Uint32Array; 372 case tcuTexture.ChannelType.UNSIGNED_INT_999_E5_REV: return Uint32Array; 373 case tcuTexture.ChannelType.UNSIGNED_INT_24_8: return Uint32Array; 374 case tcuTexture.ChannelType.FLOAT: return Float32Array; 375 case tcuTexture.ChannelType.SIGNED_INT8: return Int8Array; 376 case tcuTexture.ChannelType.SIGNED_INT16: return Int16Array; 377 case tcuTexture.ChannelType.SIGNED_INT32: return Int32Array; 378 case tcuTexture.ChannelType.UNSIGNED_INT8: return Uint8Array; 379 case tcuTexture.ChannelType.UNSIGNED_INT16: return Uint16Array; 380 case tcuTexture.ChannelType.UNSIGNED_INT32: return Uint32Array; 381 case tcuTexture.ChannelType.HALF_FLOAT: return Uint16Array; 382 case tcuTexture.ChannelType.FLOAT_UNSIGNED_INT_24_8_REV: return Float32Array; /* this type is a special case */ 383 } 384 385 throw new Error('Unrecognized type ' + type); 386 }; 387 388 /** 389 * @return {number} pixel size in bytes 390 */ 391 tcuTexture.TextureFormat.prototype.getPixelSize = function() { 392 if (this.type == null || this.order == null) { 393 // Invalid/empty format. 394 return 0; 395 } else if (this.type == tcuTexture.ChannelType.UNORM_SHORT_565 || 396 this.type == tcuTexture.ChannelType.UNORM_SHORT_555 || 397 this.type == tcuTexture.ChannelType.UNORM_SHORT_4444 || 398 this.type == tcuTexture.ChannelType.UNORM_SHORT_5551) { 399 DE_ASSERT(this.order == tcuTexture.ChannelOrder.RGB || this.order == tcuTexture.ChannelOrder.RGBA); 400 return 2; 401 } else if (this.type == tcuTexture.ChannelType.UNORM_INT_101010 || 402 this.type == tcuTexture.ChannelType.UNSIGNED_INT_999_E5_REV || 403 this.type == tcuTexture.ChannelType.UNSIGNED_INT_11F_11F_10F_REV) { 404 DE_ASSERT(this.order == tcuTexture.ChannelOrder.RGB); 405 return 4; 406 } else if (this.type == tcuTexture.ChannelType.UNORM_INT_1010102_REV || 407 this.type == tcuTexture.ChannelType.UNSIGNED_INT_1010102_REV) { 408 DE_ASSERT(this.order == tcuTexture.ChannelOrder.RGBA); 409 return 4; 410 } else if (this.type == tcuTexture.ChannelType.UNSIGNED_INT_24_8) { 411 DE_ASSERT(this.order == tcuTexture.ChannelOrder.D || this.order == tcuTexture.ChannelOrder.DS); 412 return 4; 413 } else if (this.type == tcuTexture.ChannelType.FLOAT_UNSIGNED_INT_24_8_REV) { 414 DE_ASSERT(this.order == tcuTexture.ChannelOrder.DS); 415 return 8; 416 } else { 417 var numChannels; 418 var channelSize; 419 420 switch (this.order) { 421 case tcuTexture.ChannelOrder.R: numChannels = 1; break; 422 case tcuTexture.ChannelOrder.A: numChannels = 1; break; 423 case tcuTexture.ChannelOrder.I: numChannels = 1; break; 424 case tcuTexture.ChannelOrder.L: numChannels = 1; break; 425 case tcuTexture.ChannelOrder.LA: numChannels = 2; break; 426 case tcuTexture.ChannelOrder.RG: numChannels = 2; break; 427 case tcuTexture.ChannelOrder.RA: numChannels = 2; break; 428 case tcuTexture.ChannelOrder.RGB: numChannels = 3; break; 429 case tcuTexture.ChannelOrder.RGBA: numChannels = 4; break; 430 case tcuTexture.ChannelOrder.ARGB: numChannels = 4; break; 431 case tcuTexture.ChannelOrder.BGRA: numChannels = 4; break; 432 case tcuTexture.ChannelOrder.sRGB: numChannels = 3; break; 433 case tcuTexture.ChannelOrder.sRGBA: numChannels = 4; break; 434 case tcuTexture.ChannelOrder.D: numChannels = 1; break; 435 case tcuTexture.ChannelOrder.S: numChannels = 1; break; 436 case tcuTexture.ChannelOrder.DS: numChannels = 2; break; 437 default: DE_ASSERT(false); 438 } 439 440 switch (this.type) { 441 case tcuTexture.ChannelType.SNORM_INT8: channelSize = 1; break; 442 case tcuTexture.ChannelType.SNORM_INT16: channelSize = 2; break; 443 case tcuTexture.ChannelType.SNORM_INT32: channelSize = 4; break; 444 case tcuTexture.ChannelType.UNORM_INT8: channelSize = 1; break; 445 case tcuTexture.ChannelType.UNORM_INT16: channelSize = 2; break; 446 case tcuTexture.ChannelType.UNORM_INT32: channelSize = 4; break; 447 case tcuTexture.ChannelType.SIGNED_INT8: channelSize = 1; break; 448 case tcuTexture.ChannelType.SIGNED_INT16: channelSize = 2; break; 449 case tcuTexture.ChannelType.SIGNED_INT32: channelSize = 4; break; 450 case tcuTexture.ChannelType.UNSIGNED_INT8: channelSize = 1; break; 451 case tcuTexture.ChannelType.UNSIGNED_INT16: channelSize = 2; break; 452 case tcuTexture.ChannelType.UNSIGNED_INT32: channelSize = 4; break; 453 case tcuTexture.ChannelType.HALF_FLOAT: channelSize = 2; break; 454 case tcuTexture.ChannelType.FLOAT: channelSize = 4; break; 455 default: DE_ASSERT(false); 456 } 457 458 return numChannels * channelSize; 459 } 460 }; 461 462 /** 463 * @enum 464 */ 465 tcuTexture.CubeFace = { 466 CUBEFACE_NEGATIVE_X: 0, 467 CUBEFACE_POSITIVE_X: 1, 468 CUBEFACE_NEGATIVE_Y: 2, 469 CUBEFACE_POSITIVE_Y: 3, 470 CUBEFACE_NEGATIVE_Z: 4, 471 CUBEFACE_POSITIVE_Z: 5 472 }; 473 474 /** 475 * Renamed from ArrayBuffer due to name clash 476 * Wraps ArrayBuffer. 477 * @constructor 478 * @param {number=} numElements 479 */ 480 tcuTexture.DeqpArrayBuffer = function(numElements) { 481 if (numElements) 482 this.m_ptr = new ArrayBuffer(numElements); 483 }; 484 485 /** 486 * Set array size 487 * @param {number} numElements Size in bytes 488 */ 489 tcuTexture.DeqpArrayBuffer.prototype.setStorage = function(numElements) { 490 this.m_ptr = new ArrayBuffer(numElements); 491 }; 492 493 /** 494 * @return {number} Buffer size 495 */ 496 tcuTexture.DeqpArrayBuffer.prototype.size = function() { 497 if (this.m_ptr) 498 return this.m_ptr.byteLength; 499 500 return 0; 501 }; 502 503 /** 504 * Is the buffer empty (zero size)? 505 * @return {boolean} 506 */ 507 tcuTexture.DeqpArrayBuffer.prototype.empty = function() { 508 if (!this.m_ptr) 509 return true; 510 return this.size() == 0; 511 }; 512 513 /** 514 * @enum 515 * The values are negative to avoid conflict with channels 0 - 3 516 */ 517 tcuTexture.channel = { 518 ZERO: -1, 519 ONE: -2 520 }; 521 522 /** 523 * @param {tcuTexture.ChannelOrder} order 524 * @return {Array<Number|tcuTexture.channel>} 525 */ 526 tcuTexture.getChannelReadMap = function(order) { 527 switch (order) { 528 /*static const Channel INV[] = { tcuTexture.channel.ZERO, tcuTexture.channel.ZERO, tcuTexture.channel.ZERO, tcuTexture.channel.ONE }; */ 529 530 case tcuTexture.ChannelOrder.R: return [0, tcuTexture.channel.ZERO, tcuTexture.channel.ZERO, tcuTexture.channel.ONE]; 531 case tcuTexture.ChannelOrder.A: return [tcuTexture.channel.ZERO, tcuTexture.channel.ZERO, tcuTexture.channel.ZERO, 0]; 532 case tcuTexture.ChannelOrder.I: return [0, 0, 0, 0]; 533 case tcuTexture.ChannelOrder.L: return [0, 0, 0, tcuTexture.channel.ONE]; 534 case tcuTexture.ChannelOrder.LA: return [0, 0, 0, 1]; 535 case tcuTexture.ChannelOrder.RG: return [0, 1, tcuTexture.channel.ZERO, tcuTexture.channel.ONE]; 536 case tcuTexture.ChannelOrder.RA: return [0, tcuTexture.channel.ZERO, tcuTexture.channel.ZERO, 1]; 537 case tcuTexture.ChannelOrder.RGB: return [0, 1, 2, tcuTexture.channel.ONE]; 538 case tcuTexture.ChannelOrder.RGBA: return [0, 1, 2, 3]; 539 case tcuTexture.ChannelOrder.BGRA: return [2, 1, 0, 3]; 540 case tcuTexture.ChannelOrder.ARGB: return [1, 2, 3, 0]; 541 case tcuTexture.ChannelOrder.sRGB: return [0, 1, 2, tcuTexture.channel.ONE]; 542 case tcuTexture.ChannelOrder.sRGBA: return [0, 1, 2, 3]; 543 case tcuTexture.ChannelOrder.D: return [0, tcuTexture.channel.ZERO, tcuTexture.channel.ZERO, tcuTexture.channel.ONE]; 544 case tcuTexture.ChannelOrder.S: return [tcuTexture.channel.ZERO, tcuTexture.channel.ZERO, tcuTexture.channel.ZERO, 0]; 545 case tcuTexture.ChannelOrder.DS: return [0, tcuTexture.channel.ZERO, tcuTexture.channel.ZERO, 1]; 546 } 547 548 throw new Error('Unrecognized order ' + order); 549 }; 550 551 /** 552 * @param {tcuTexture.ChannelOrder} order 553 * @return {Array<number>} 554 */ 555 tcuTexture.getChannelWriteMap = function(order) { 556 switch (order) { 557 case tcuTexture.ChannelOrder.R: return [0]; 558 case tcuTexture.ChannelOrder.A: return [3]; 559 case tcuTexture.ChannelOrder.I: return [0]; 560 case tcuTexture.ChannelOrder.L: return [0]; 561 case tcuTexture.ChannelOrder.LA: return [0, 3]; 562 case tcuTexture.ChannelOrder.RG: return [0, 1]; 563 case tcuTexture.ChannelOrder.RA: return [0, 3]; 564 case tcuTexture.ChannelOrder.RGB: return [0, 1, 2]; 565 case tcuTexture.ChannelOrder.RGBA: return [0, 1, 2, 3]; 566 case tcuTexture.ChannelOrder.ARGB: return [3, 0, 1, 2]; 567 case tcuTexture.ChannelOrder.BGRA: return [2, 1, 0, 3]; 568 case tcuTexture.ChannelOrder.sRGB: return [0, 1, 2]; 569 case tcuTexture.ChannelOrder.sRGBA: return [0, 1, 2, 3]; 570 case tcuTexture.ChannelOrder.D: return [0]; 571 case tcuTexture.ChannelOrder.S: return [3]; 572 case tcuTexture.ChannelOrder.DS: return [0, 3]; 573 } 574 throw new Error('Unrecognized order ' + order); 575 }; 576 577 /** 578 * @param {tcuTexture.ChannelType} type 579 * @return {number} 580 */ 581 tcuTexture.getChannelSize = function(type) { 582 switch (type) { 583 case tcuTexture.ChannelType.SNORM_INT8: return 1; 584 case tcuTexture.ChannelType.SNORM_INT16: return 2; 585 case tcuTexture.ChannelType.SNORM_INT32: return 4; 586 case tcuTexture.ChannelType.UNORM_INT8: return 1; 587 case tcuTexture.ChannelType.UNORM_INT16: return 2; 588 case tcuTexture.ChannelType.UNORM_INT32: return 4; 589 case tcuTexture.ChannelType.SIGNED_INT8: return 1; 590 case tcuTexture.ChannelType.SIGNED_INT16: return 2; 591 case tcuTexture.ChannelType.SIGNED_INT32: return 4; 592 case tcuTexture.ChannelType.UNSIGNED_INT8: return 1; 593 case tcuTexture.ChannelType.UNSIGNED_INT16: return 2; 594 case tcuTexture.ChannelType.UNSIGNED_INT32: return 4; 595 case tcuTexture.ChannelType.UNSIGNED_INT_11F_11F_10F_REV: return 4; 596 case tcuTexture.ChannelType.UNSIGNED_INT_999_E5_REV: return 4; 597 case tcuTexture.ChannelType.HALF_FLOAT: return 2; 598 case tcuTexture.ChannelType.FLOAT: return 4; 599 600 } 601 throw new Error('Unrecognized type ' + deString.enumToString(tcuTexture.ChannelType, type)); 602 }; 603 604 /** 605 * @param {number} src Source value 606 * @param {number} bits Source value size in bits 607 * @return {number} Normalized value 608 */ 609 tcuTexture.channelToNormFloat = function(src, bits) { 610 var maxVal = (1 << bits) - 1; 611 return src / maxVal; 612 }; 613 614 /** 615 * @param {number} value Source value 616 * @param {tcuTexture.ChannelType} type 617 * @return {number} Source value converted to float 618 */ 619 tcuTexture.channelToFloat = function(value, type) { 620 switch (type) { 621 case tcuTexture.ChannelType.SNORM_INT8: return Math.max(-1, value / 127); 622 case tcuTexture.ChannelType.SNORM_INT16: return Math.max(-1, value / 32767); 623 case tcuTexture.ChannelType.SNORM_INT32: return Math.max(-1, value / 2147483647); 624 case tcuTexture.ChannelType.UNORM_INT8: return value / 255; 625 case tcuTexture.ChannelType.UNORM_INT16: return value / 65535; 626 case tcuTexture.ChannelType.UNORM_INT32: return value / 4294967295; 627 case tcuTexture.ChannelType.SIGNED_INT8: return value; 628 case tcuTexture.ChannelType.SIGNED_INT16: return value; 629 case tcuTexture.ChannelType.SIGNED_INT32: return value; 630 case tcuTexture.ChannelType.UNSIGNED_INT8: return value; 631 case tcuTexture.ChannelType.UNSIGNED_INT16: return value; 632 case tcuTexture.ChannelType.UNSIGNED_INT32: return value; 633 case tcuTexture.ChannelType.HALF_FLOAT: return tcuFloat.halfFloatToNumber(value); 634 case tcuTexture.ChannelType.FLOAT: return value; 635 } 636 throw new Error('Unrecognized tcuTexture.channel type ' + type); 637 }; 638 639 /** 640 * @param {number} value Source value 641 * @param {tcuTexture.ChannelType} type 642 * @return {number} Source value converted to int 643 */ 644 tcuTexture.channelToInt = function(value, type) { 645 switch (type) { 646 case tcuTexture.ChannelType.HALF_FLOAT: return Math.round(tcuFloat.halfFloatToNumber(value)); 647 case tcuTexture.ChannelType.FLOAT: return Math.round(value); 648 default: 649 return value; 650 } 651 }; 652 653 /** 654 * @param {tcuTexture.ChannelOrder} order 655 * @return {number} 656 */ 657 tcuTexture.getNumUsedChannels = function(order) { 658 switch (order) { 659 case tcuTexture.ChannelOrder.R: return 1; 660 case tcuTexture.ChannelOrder.A: return 1; 661 case tcuTexture.ChannelOrder.I: return 1; 662 case tcuTexture.ChannelOrder.L: return 1; 663 case tcuTexture.ChannelOrder.LA: return 2; 664 case tcuTexture.ChannelOrder.RG: return 2; 665 case tcuTexture.ChannelOrder.RA: return 2; 666 case tcuTexture.ChannelOrder.RGB: return 3; 667 case tcuTexture.ChannelOrder.RGBA: return 4; 668 case tcuTexture.ChannelOrder.ARGB: return 4; 669 case tcuTexture.ChannelOrder.BGRA: return 4; 670 case tcuTexture.ChannelOrder.sRGB: return 3; 671 case tcuTexture.ChannelOrder.sRGBA: return 4; 672 case tcuTexture.ChannelOrder.D: return 1; 673 case tcuTexture.ChannelOrder.S: return 1; 674 case tcuTexture.ChannelOrder.DS: return 2; 675 } 676 throw new Error('Unrecognized tcuTexture.channel order ' + order); 677 }; 678 679 /** 680 * @enum 681 */ 682 tcuTexture.WrapMode = { 683 CLAMP_TO_EDGE: 0, //! Clamp to edge 684 CLAMP_TO_BORDER: 1, //! Use border color at edge 685 REPEAT_GL: 2, //! Repeat with OpenGL semantics 686 REPEAT_CL: 3, //! Repeat with OpenCL semantics 687 MIRRORED_REPEAT_GL: 4, //! Mirrored repeat with OpenGL semantics 688 MIRRORED_REPEAT_CL: 5 //! Mirrored repeat with OpenCL semantics 689 }; 690 691 /** 692 * @enum 693 */ 694 tcuTexture.FilterMode = { 695 NEAREST: 0, 696 LINEAR: 1, 697 698 NEAREST_MIPMAP_NEAREST: 2, 699 NEAREST_MIPMAP_LINEAR: 3, 700 LINEAR_MIPMAP_NEAREST: 4, 701 LINEAR_MIPMAP_LINEAR: 5 702 }; 703 704 /** 705 * @enum 706 */ 707 tcuTexture.CompareMode = { 708 COMPAREMODE_NONE: 0, 709 COMPAREMODE_LESS: 1, 710 COMPAREMODE_LESS_OR_EQUAL: 2, 711 COMPAREMODE_GREATER: 3, 712 COMPAREMODE_GREATER_OR_EQUAL: 4, 713 COMPAREMODE_EQUAL: 5, 714 COMPAREMODE_NOT_EQUAL: 6, 715 COMPAREMODE_ALWAYS: 7, 716 COMPAREMODE_NEVER: 8 717 }; 718 719 /** 720 * @constructor 721 * @param {!tcuTexture.WrapMode} wrapS 722 * @param {!tcuTexture.WrapMode} wrapT 723 * @param {!tcuTexture.WrapMode} wrapR 724 * @param {!tcuTexture.FilterMode} minFilter 725 * @param {!tcuTexture.FilterMode} magFilter 726 * @param {number=} lodThreshold 727 * @param {boolean=} normalizedCoords 728 * @param {tcuTexture.CompareMode=} compare 729 * @param {number=} compareChannel 730 * @param {Array<number>=} borderColor 731 * @param {boolean=} seamlessCubeMap 732 */ 733 tcuTexture.Sampler = function(wrapS, wrapT, wrapR, minFilter, magFilter, lodThreshold, normalizedCoords, compare, compareChannel, borderColor, seamlessCubeMap) { 734 /** @type {!tcuTexture.WrapMode} */ this.wrapS = wrapS; 735 /** @type {!tcuTexture.WrapMode} */ this.wrapT = wrapT; 736 /** @type {!tcuTexture.WrapMode} */ this.wrapR = wrapR; 737 /** @type {!tcuTexture.FilterMode} */ this.minFilter = minFilter; 738 /** @type {!tcuTexture.FilterMode} */ this.magFilter = magFilter; 739 this.lodThreshold = lodThreshold || 0; 740 this.normalizedCoords = normalizedCoords === undefined ? true : normalizedCoords; 741 /** @type {tcuTexture.CompareMode} */ this.compare = compare || tcuTexture.CompareMode.COMPAREMODE_NONE; 742 this.compareChannel = compareChannel || 0; 743 this.borderColor = borderColor || [0, 0, 0, 0]; 744 this.seamlessCubeMap = seamlessCubeMap || false; 745 }; 746 747 /** 748 * Special unnormalization for REPEAT_CL and MIRRORED_REPEAT_CL tcuTexture.wrap modes; otherwise ordinary unnormalization. 749 * @param {tcuTexture.WrapMode} mode 750 * @param {number} c Value to tcuTexture.unnormalize 751 * @param {number} size Unnormalized type size (integer) 752 * @return {number} 753 */ 754 tcuTexture.unnormalize = function(mode, c, size) { 755 switch (mode) { 756 case tcuTexture.WrapMode.CLAMP_TO_EDGE: 757 case tcuTexture.WrapMode.CLAMP_TO_BORDER: 758 case tcuTexture.WrapMode.REPEAT_GL: 759 case tcuTexture.WrapMode.MIRRORED_REPEAT_GL: // Fall-through (ordinary case). 760 return size * c; 761 762 case tcuTexture.WrapMode.REPEAT_CL: 763 return size * (c - Math.floor(c)); 764 765 case tcuTexture.WrapMode.MIRRORED_REPEAT_CL: 766 return size * Math.abs(c - 2 * deMath.rint(0.5 * c)); 767 } 768 throw new Error('Unrecognized tcuTexture.wrap mode ' + mode); 769 }; 770 771 /** 772 * @param {tcuTexture.WrapMode} mode 773 * @param {number} c Source value (integer) 774 * @param {number} size Type size (integer) 775 * @return {number} 776 */ 777 tcuTexture.wrap = function(mode, c, size) { 778 switch (mode) { 779 case tcuTexture.WrapMode.CLAMP_TO_BORDER: 780 return deMath.clamp(c, -1, size); 781 782 case tcuTexture.WrapMode.CLAMP_TO_EDGE: 783 return deMath.clamp(c, 0, size - 1); 784 785 case tcuTexture.WrapMode.REPEAT_GL: 786 return deMath.imod(c, size); 787 788 case tcuTexture.WrapMode.REPEAT_CL: 789 return deMath.imod(c, size); 790 791 case tcuTexture.WrapMode.MIRRORED_REPEAT_GL: 792 return (size - 1) - deMath.mirror(deMath.imod(c, 2 * size) - size); 793 794 case tcuTexture.WrapMode.MIRRORED_REPEAT_CL: 795 return deMath.clamp(c, 0, size - 1); // \note Actual mirroring done already in unnormalization function. 796 } 797 throw new Error('Unrecognized tcuTexture.wrap mode ' + mode); 798 }; 799 800 /** 801 * @param {number} cs 802 * @return {number} 803 */ 804 tcuTexture.sRGBChannelToLinear = function(cs) { 805 if (cs <= 0.04045) 806 return cs / 12.92; 807 else 808 return Math.pow((cs + 0.055) / 1.055, 2.4); 809 }; 810 811 /** 812 * Convert sRGB to linear colorspace 813 * @param {Array<number>} cs Vec4 814 * @return {Array<number>} Vec4 815 */ 816 tcuTexture.sRGBToLinear = function(cs) { 817 return [ 818 tcuTexture.sRGBChannelToLinear(cs[0]), 819 tcuTexture.sRGBChannelToLinear(cs[1]), 820 tcuTexture.sRGBChannelToLinear(cs[2]), 821 cs[3] 822 ]; 823 }; 824 825 /** 826 * Texel tcuTexture.lookup with color conversion. 827 * @param {tcuTexture.ConstPixelBufferAccess} access 828 * @param {number} i 829 * @param {number} j 830 * @param {number} k 831 * @return {Array<number>} Vec4 pixel color 832 */ 833 tcuTexture.lookup = function(access, i, j, k) { 834 var p = access.getPixel(i, j, k); 835 return access.getFormat().isSRGB() ? tcuTexture.sRGBToLinear(p) : p; 836 }; 837 838 /** 839 * @param {tcuTexture.ConstPixelBufferAccess} access 840 * @param {tcuTexture.Sampler} sampler 841 * @param {number} u 842 * @param {number} v 843 * @param {(number|Array<number>)} depthOrOffset depth (int) or offset (ivec3) 844 * @return {Array<number>} Vec4 pixel color 845 */ 846 tcuTexture.sampleLinear2D = function(access, sampler, u, v, depthOrOffset) { 847 /** @type {number} */ var xOffset = 0; 848 /** @type {number} */ var yOffset = 0; 849 /** @type {number} */ var value; 850 if (Array.isArray(depthOrOffset)) { 851 xOffset = depthOrOffset[0]; 852 yOffset = depthOrOffset[1]; 853 value = depthOrOffset[2]; 854 } else { 855 value = /** @type {number} */ (depthOrOffset); 856 } 857 858 /** 859 * @param {Array<number>} p00 860 * @param {Array<number>} p10 861 * @param {Array<number>} p01 862 * @param {Array<number>} p11 863 * @param {number} a 864 * @param {number} b 865 */ 866 var interpolateQuad = function(p00, p10, p01, p11, a, b) { 867 var s00 = (1 - a) * (1 - b); 868 var s10 = a * (1 - b); 869 var s01 = (1 - a) * b; 870 var s11 = a * b; 871 872 return [ 873 (p00[0] * s00) + (p10[0] * s10) + (p01[0] * s01) + (p11[0] * s11), 874 (p00[1] * s00) + (p10[1] * s10) + (p01[1] * s01) + (p11[1] * s11), 875 (p00[2] * s00) + (p10[2] * s10) + (p01[2] * s01) + (p11[2] * s11), 876 (p00[3] * s00) + (p10[3] * s10) + (p01[3] * s01) + (p11[3] * s11) 877 ]; 878 }; 879 880 var w = access.getWidth(); 881 var h = access.getHeight(); 882 883 var x0 = Math.floor(u - 0.5) + xOffset; 884 var x1 = x0 + 1; 885 var y0 = Math.floor(v - 0.5) + yOffset; 886 var y1 = y0 + 1; 887 888 var i0 = tcuTexture.wrap(sampler.wrapS, x0, w); 889 var i1 = tcuTexture.wrap(sampler.wrapS, x1, w); 890 var j0 = tcuTexture.wrap(sampler.wrapT, y0, h); 891 var j1 = tcuTexture.wrap(sampler.wrapT, y1, h); 892 893 var a = deMath.deFloatFrac(u - 0.5); 894 var b = deMath.deFloatFrac(v - 0.5); 895 896 var i0UseBorder = sampler.wrapS == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(i0, 0, w); 897 var i1UseBorder = sampler.wrapS == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(i1, 0, w); 898 var j0UseBorder = sampler.wrapT == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(j0, 0, h); 899 var j1UseBorder = sampler.wrapT == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(j1, 0, h); 900 901 // Border color for out-of-range coordinates if using CLAMP_TO_BORDER, otherwise execute lookups. 902 var p00 = (i0UseBorder || j0UseBorder) ? sampler.borderColor : tcuTexture.lookup(access, i0, j0, value); 903 var p10 = (i1UseBorder || j0UseBorder) ? sampler.borderColor : tcuTexture.lookup(access, i1, j0, value); 904 var p01 = (i0UseBorder || j1UseBorder) ? sampler.borderColor : tcuTexture.lookup(access, i0, j1, value); 905 var p11 = (i1UseBorder || j1UseBorder) ? sampler.borderColor : tcuTexture.lookup(access, i1, j1, value); 906 907 // Interpolate. 908 return interpolateQuad(p00, p10, p01, p11, a, b); 909 }; 910 911 /** 912 * @param {tcuTexture.ConstPixelBufferAccess} access 913 * @param {tcuTexture.Sampler} sampler 914 * @param {number} u 915 * @param {number} v 916 * @param {number} w 917 * @param {Array<number>=} offset 918 * @return {Array<number>} Vec4 pixel color 919 */ 920 tcuTexture.sampleLinear3D = function(access, sampler, u, v, w, offset) { 921 /** 922 * @param {Array<number>} p000 923 * @param {Array<number>} p100 924 * @param {Array<number>} p010 925 * @param {Array<number>} p110 926 * @param {Array<number>} p001 927 * @param {Array<number>} p101 928 * @param {Array<number>} p011 929 * @param {Array<number>} p111 930 * @param {number} a 931 * @param {number} b 932 * @param {number} c 933 */ 934 var interpolateCube = function(p000, p100, p010, p110, p001, p101, p011, p111, a, b, c) { 935 var s000 = (1 - a) * (1 - b) * (1 - c); 936 var s100 = a * (1 - b) * (1 - c); 937 var s010 = (1 - a) * b * (1 - c); 938 var s110 = a * b * (1 - c); 939 var s001 = (1 - a) * (1 - b) * c; 940 var s101 = a * (1 - b) * c; 941 var s011 = (1 - a) * b * c; 942 var s111 = a * b * c; 943 944 return [ 945 (p000[0] * s000) + (p100[0] * s100) + (p010[0] * s010) + (p110[0] * s110) + (p001[0] * s001) + (p101[0] * s101) + (p011[0] * s011) + (p111[0] * s111), 946 (p000[1] * s000) + (p100[1] * s100) + (p010[1] * s010) + (p110[1] * s110) + (p001[1] * s001) + (p101[1] * s101) + (p011[1] * s011) + (p111[1] * s111), 947 (p000[2] * s000) + (p100[2] * s100) + (p010[2] * s010) + (p110[2] * s110) + (p001[2] * s001) + (p101[2] * s101) + (p011[2] * s011) + (p111[2] * s111), 948 (p000[3] * s000) + (p100[3] * s100) + (p010[3] * s010) + (p110[3] * s110) + (p001[3] * s001) + (p101[3] * s101) + (p011[3] * s011) + (p111[3] * s111) 949 ]; 950 }; 951 952 var width = access.getWidth(); 953 var height = access.getHeight(); 954 var depth = access.getDepth(); 955 956 /** @type {number} */ var xOffset = 0; 957 /** @type {number} */ var yOffset = 0; 958 /** @type {number} */ var zOffset = 0; 959 960 if (offset !== undefined && offset.length === 3) { 961 xOffset = offset[0]; 962 yOffset = offset[1]; 963 zOffset = offset[2]; 964 } 965 966 var x0 = Math.floor(u - 0.5) + xOffset; 967 var x1 = x0 + 1; 968 var y0 = Math.floor(v - 0.5) + yOffset; 969 var y1 = y0 + 1; 970 var z0 = Math.floor(w - 0.5) + zOffset; 971 var z1 = z0 + 1; 972 973 var i0 = tcuTexture.wrap(sampler.wrapS, x0, width); 974 var i1 = tcuTexture.wrap(sampler.wrapS, x1, width); 975 var j0 = tcuTexture.wrap(sampler.wrapT, y0, height); 976 var j1 = tcuTexture.wrap(sampler.wrapT, y1, height); 977 var k0 = tcuTexture.wrap(sampler.wrapR, z0, depth); 978 var k1 = tcuTexture.wrap(sampler.wrapR, z1, depth); 979 980 var a = deMath.deFloatFrac(u - 0.5); 981 var b = deMath.deFloatFrac(v - 0.5); 982 var c = deMath.deFloatFrac(w - 0.5); 983 984 var i0UseBorder = sampler.wrapS == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(i0, 0, width); 985 var i1UseBorder = sampler.wrapS == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(i1, 0, width); 986 var j0UseBorder = sampler.wrapT == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(j0, 0, height); 987 var j1UseBorder = sampler.wrapT == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(j1, 0, height); 988 var k0UseBorder = sampler.wrapR == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(k0, 0, depth); 989 var k1UseBorder = sampler.wrapR == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(k1, 0, depth); 990 991 // Border color for out-of-range coordinates if using CLAMP_TO_BORDER, otherwise execute lookups. 992 var p000 = (i0UseBorder || j0UseBorder || k0UseBorder) ? sampler.borderColor : tcuTexture.lookup(access, i0, j0, k0); 993 var p100 = (i1UseBorder || j0UseBorder || k0UseBorder) ? sampler.borderColor : tcuTexture.lookup(access, i1, j0, k0); 994 var p010 = (i0UseBorder || j1UseBorder || k0UseBorder) ? sampler.borderColor : tcuTexture.lookup(access, i0, j1, k0); 995 var p110 = (i1UseBorder || j1UseBorder || k0UseBorder) ? sampler.borderColor : tcuTexture.lookup(access, i1, j1, k0); 996 var p001 = (i0UseBorder || j0UseBorder || k1UseBorder) ? sampler.borderColor : tcuTexture.lookup(access, i0, j0, k1); 997 var p101 = (i1UseBorder || j0UseBorder || k1UseBorder) ? sampler.borderColor : tcuTexture.lookup(access, i1, j0, k1); 998 var p011 = (i0UseBorder || j1UseBorder || k1UseBorder) ? sampler.borderColor : tcuTexture.lookup(access, i0, j1, k1); 999 var p111 = (i1UseBorder || j1UseBorder || k1UseBorder) ? sampler.borderColor : tcuTexture.lookup(access, i1, j1, k1); 1000 1001 // Interpolate. 1002 return interpolateCube(p000, p100, p010, p110, p001, p101, p011, p111, a, b, c); 1003 }; 1004 1005 /** 1006 * @param {tcuTexture.ConstPixelBufferAccess} access 1007 * @param {tcuTexture.Sampler} sampler 1008 * @param {number} u 1009 * @param {number} v 1010 * @param {(number|Array<number>)} depthOrOffset depth (integer) or offset (ivec3) 1011 * @return {Array<number>} Vec4 pixel color 1012 */ 1013 tcuTexture.sampleNearest2D = function(access, sampler, u, v, depthOrOffset) { 1014 /** @type {number} */ var xOffset = 0; 1015 /** @type {number} */ var yOffset = 0; 1016 /** @type {number} */ var value; 1017 if (Array.isArray(depthOrOffset)) { 1018 xOffset = depthOrOffset[0]; 1019 yOffset = depthOrOffset[1]; 1020 value = depthOrOffset[2]; 1021 } else { 1022 value = /** @type {number} */ (depthOrOffset); 1023 } 1024 1025 var width = access.getWidth(); 1026 var height = access.getHeight(); 1027 1028 var x = Math.floor(u) + xOffset; 1029 var y = Math.floor(v) + yOffset; 1030 1031 // Check for CLAMP_TO_BORDER. 1032 if ((sampler.wrapS == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(x, 0, width)) || 1033 (sampler.wrapT == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(y, 0, height))) 1034 return sampler.borderColor; 1035 1036 var i = tcuTexture.wrap(sampler.wrapS, x, width); 1037 var j = tcuTexture.wrap(sampler.wrapT, y, height); 1038 1039 return tcuTexture.lookup(access, i, j, value); 1040 }; 1041 1042 /** 1043 * @param {tcuTexture.ConstPixelBufferAccess} access 1044 * @param {tcuTexture.Sampler} sampler 1045 * @param {number} u 1046 * @param {number} v 1047 * @param {number} w 1048 * @param {Array<number>=} offset 1049 * @return {Array<number>} Vec4 pixel color 1050 */ 1051 tcuTexture.sampleNearest3D = function(access, sampler, u, v, w, offset) { 1052 var width = access.getWidth(); 1053 var height = access.getHeight(); 1054 var depth = access.getDepth(); 1055 /** @type {number} */ var xOffset = 0; 1056 /** @type {number} */ var yOffset = 0; 1057 /** @type {number} */ var zOffset = 0; 1058 1059 if (offset !== undefined && offset.length === 3) { 1060 xOffset = offset[0]; 1061 yOffset = offset[1]; 1062 zOffset = offset[2]; 1063 } 1064 1065 var x = Math.floor(u) + xOffset; 1066 var y = Math.floor(v) + yOffset; 1067 var z = Math.floor(w) + zOffset; 1068 1069 // Check for CLAMP_TO_BORDER. 1070 if ((sampler.wrapS == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(x, 0, width)) || 1071 (sampler.wrapT == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(y, 0, height)) || 1072 (sampler.wrapR == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(z, 0, depth))) 1073 return sampler.borderColor; 1074 1075 var i = tcuTexture.wrap(sampler.wrapS, x, width); 1076 var j = tcuTexture.wrap(sampler.wrapT, y, height); 1077 var k = tcuTexture.wrap(sampler.wrapR, z, depth); 1078 1079 return tcuTexture.lookup(access, i, j, k); 1080 }; 1081 1082 /** 1083 * @param {Array<number>} color Vec4 color 1084 * @return {number} The color in packed 32 bit format 1085 */ 1086 tcuTexture.packRGB999E5 = function(color) { 1087 /** @const */ var mBits = 9; 1088 /** @const */ var eBits = 5; 1089 /** @const */ var eBias = 15; 1090 /** @const */ var eMax = (1 << eBits) - 1; 1091 /** @const */ var maxVal = (((1 << mBits) - 1) * (1 << (eMax - eBias))) / (1 << mBits); 1092 1093 var rc = deMath.clamp(color[0], 0, maxVal); 1094 var gc = deMath.clamp(color[1], 0, maxVal); 1095 var bc = deMath.clamp(color[2], 0, maxVal); 1096 var maxc = Math.max(rc, gc, bc); 1097 var expp = Math.max(-eBias - 1, Math.floor(Math.log2(maxc))) + 1 + eBias; 1098 var e = Math.pow(2, expp - eBias - mBits); 1099 var maxs = Math.floor(maxc / e + 0.5); 1100 1101 var exps = maxs == (1 << mBits) ? expp + 1 : expp; 1102 var rs = deMath.clamp(Math.floor(rc / e + 0.5), 0, (1 << 9) - 1); 1103 var gs = deMath.clamp(Math.floor(gc / e + 0.5), 0, (1 << 9) - 1); 1104 var bs = deMath.clamp(Math.floor(bc / e + 0.5), 0, (1 << 9) - 1); 1105 1106 DE_ASSERT((exps & ~((1 << 5) - 1)) == 0); 1107 DE_ASSERT((rs & ~((1 << 9) - 1)) == 0); 1108 DE_ASSERT((gs & ~((1 << 9) - 1)) == 0); 1109 DE_ASSERT((bs & ~((1 << 9) - 1)) == 0); 1110 1111 return rs | (gs << 9) | (bs << 18) | (exps << 27); 1112 }; 1113 1114 /** 1115 * @param {number} color Color in packed 32 bit format 1116 * @return {Array<number>} The color in unpacked format 1117 */ 1118 tcuTexture.unpackRGB999E5 = function(color) { 1119 var mBits = 9; 1120 var eBias = 15; 1121 1122 var exp = (color >> 27) & ((1 << 5) - 1); 1123 var bs = (color >> 18) & ((1 << 9) - 1); 1124 var gs = (color >> 9) & ((1 << 9) - 1); 1125 var rs = color & ((1 << 9) - 1); 1126 1127 var e = Math.pow(2, (exp - eBias - mBits)); 1128 var r = rs * e; 1129 var g = gs * e; 1130 var b = bs * e; 1131 1132 return [r, g, b, 1]; 1133 }; 1134 1135 /** 1136 * \brief Read-only pixel data access 1137 * 1138 * tcuTexture.ConstPixelBufferAccess encapsulates pixel data pointer along with 1139 * format and layout information. It can be used for read-only access 1140 * to arbitrary pixel buffers. 1141 * 1142 * Access objects are like iterators or pointers. They can be passed around 1143 * as values and are valid as long as the storage doesn't change. 1144 * @constructor 1145 */ 1146 tcuTexture.ConstPixelBufferAccess = function(descriptor) { 1147 if (descriptor) { 1148 this.m_offset = descriptor.offset || 0; 1149 this.m_format = descriptor.format || new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.FLOAT); 1150 this.m_width = descriptor.width; 1151 this.m_height = descriptor.height; 1152 if (descriptor.depth) 1153 this.m_depth = descriptor.depth; 1154 else 1155 this.m_depth = 1; 1156 this.m_data = descriptor.data; 1157 if (descriptor.rowPitch) 1158 this.m_rowPitch = descriptor.rowPitch; 1159 else 1160 this.m_rowPitch = this.m_width * this.m_format.getPixelSize(); 1161 1162 if (descriptor.slicePitch) 1163 this.m_slicePitch = descriptor.slicePitch; 1164 else 1165 this.m_slicePitch = this.m_rowPitch * this.m_height; 1166 1167 if (this.m_format.isEqual(new tcuTexture.TextureFormat( 1168 tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT8))) 1169 this.m_rgba8View = new tcuTexture.RGBA8View(this); 1170 else if (this.m_format.isEqual(new tcuTexture.TextureFormat( 1171 tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.UNORM_INT8))) 1172 this.m_rgb8View = new tcuTexture.RGBA8View(this); 1173 1174 } 1175 1176 this.m_dataPtrType = null; 1177 this.m_dataPtr = null; 1178 }; 1179 1180 tcuTexture.ConstPixelBufferAccess.prototype.toString = function() { 1181 var str = 'BufferAccess(format: ' + this.m_format + 1182 ', width: ' + this.m_width + 1183 ', height: ' + this.m_height; 1184 if (this.m_depth > 1) 1185 str += ', depth: ' + this.m_depth; 1186 if (this.m_rowPitch != this.m_width * this.m_format.getPixelSize()) 1187 str += ', row pitch: ' + this.m_rowPitch; 1188 if (this.m_slicePitch != this.m_rowPitch * this.m_height) 1189 str += ', slice pitch: ' + this.m_slicePitch; 1190 if (this.m_offset > 0) 1191 str += ', offset: ' + this.m_offset; 1192 str += ')'; 1193 return str; 1194 }; 1195 1196 /** @return {number} */ 1197 tcuTexture.ConstPixelBufferAccess.prototype.getDataSize = function() { return this.m_depth * this.m_slicePitch; }; 1198 tcuTexture.ConstPixelBufferAccess.prototype.isEmpty = function() { return this.m_width == 0 || this.m_height == 0 || this.m_depth == 0; }; 1199 /** @return {goog.TypedArray} */ 1200 tcuTexture.ConstPixelBufferAccess.prototype.getDataPtr = function() { 1201 if (this.m_dataPtrType != this.m_format.type) { 1202 this.m_dataPtrType = this.m_format.type; 1203 var arrayType = tcuTexture.getTypedArray(this.m_format.type); 1204 this.m_dataPtr = new arrayType(this.m_data, this.m_offset); 1205 } 1206 return this.m_dataPtr; 1207 }; 1208 /** @return {ArrayBuffer} */ 1209 tcuTexture.ConstPixelBufferAccess.prototype.getBuffer = function() { 1210 return this.m_data; 1211 }; 1212 /** @return {number} */ 1213 tcuTexture.ConstPixelBufferAccess.prototype.getRowPitch = function() { return this.m_rowPitch; }; 1214 /** @return {number} */ 1215 tcuTexture.ConstPixelBufferAccess.prototype.getWidth = function() { return this.m_width; }; 1216 /** @return {number} */ 1217 tcuTexture.ConstPixelBufferAccess.prototype.getHeight = function() { return this.m_height; }; 1218 /** @return {number} */ 1219 tcuTexture.ConstPixelBufferAccess.prototype.getDepth = function() { return this.m_depth; }; 1220 /** @return {number} */ 1221 tcuTexture.ConstPixelBufferAccess.prototype.getSlicePitch = function() { return this.m_slicePitch; }; 1222 /** @return {tcuTexture.TextureFormat} */ 1223 tcuTexture.ConstPixelBufferAccess.prototype.getFormat = function() { return this.m_format; }; 1224 1225 /** 1226 * @param {number} x 1227 * @param {number} y 1228 * @param {number=} z 1229 * @return {number} stencil value 1230 */ 1231 tcuTexture.ConstPixelBufferAccess.prototype.getPixStencil = function(x, y, z) { 1232 z = z || 0; 1233 1234 DE_ASSERT(deMath.deInBounds32(x, 0, this.m_width)); 1235 DE_ASSERT(deMath.deInBounds32(y, 0, this.m_height)); 1236 DE_ASSERT(deMath.deInBounds32(z, 0, this.m_depth)); 1237 1238 // Make sure that the position is 'integer' 1239 x = Math.round(x); 1240 y = Math.round(y); 1241 z = Math.round(z); 1242 1243 var pixelSize = this.m_format.getPixelSize(); 1244 var offset = z * this.m_slicePitch + y * this.m_rowPitch + x * pixelSize; 1245 var pixelPtr = this.getDataPtr(); 1246 var pixelPtrOffset = offset / pixelPtr.BYTES_PER_ELEMENT; 1247 1248 switch (this.m_format.type) { 1249 case tcuTexture.ChannelType.UNSIGNED_INT_24_8: 1250 switch (this.m_format.order) { 1251 case tcuTexture.ChannelOrder.S: return (pixelPtr[pixelPtrOffset] >> 8) & 0xff; 1252 case tcuTexture.ChannelOrder.DS: return pixelPtr[pixelPtrOffset] & 0xff; 1253 1254 default: 1255 DE_ASSERT(false); 1256 return 0; 1257 } 1258 1259 case tcuTexture.ChannelType.FLOAT_UNSIGNED_INT_24_8_REV: 1260 DE_ASSERT(this.m_format.order == tcuTexture.ChannelOrder.DS); 1261 var u32array = new Uint32Array(this.m_data, offset + this.m_offset + 4, 1); 1262 return u32array[0] & 0xff; 1263 1264 default: { 1265 if (this.m_format.order == tcuTexture.ChannelOrder.S) 1266 return tcuTexture.channelToInt(pixelPtr[pixelPtrOffset], this.m_format.type); 1267 else { 1268 DE_ASSERT(this.m_format.order == tcuTexture.ChannelOrder.DS); 1269 var stencilChannelIndex = 3; 1270 return tcuTexture.channelToInt(pixelPtr[stencilChannelIndex + pixelPtrOffset], this.m_format.type); 1271 } 1272 } 1273 } 1274 }; 1275 1276 /** 1277 * @param {number} x 1278 * @param {number} y 1279 * @param {number=} z 1280 * @return {number} 1281 */ 1282 tcuTexture.ConstPixelBufferAccess.prototype.getPixDepth = function(x, y, z) { 1283 if (z == null) 1284 z = 0; 1285 DE_ASSERT(deMath.deInBounds32(x, 0, this.m_width)); 1286 DE_ASSERT(deMath.deInBounds32(y, 0, this.m_height)); 1287 DE_ASSERT(deMath.deInBounds32(z, 0, this.m_depth)); 1288 1289 // Make sure that the position is 'integer' 1290 x = Math.round(x); 1291 y = Math.round(y); 1292 z = Math.round(z); 1293 1294 var pixelSize = this.m_format.getPixelSize(); 1295 var offset = z * this.m_slicePitch + y * this.m_rowPitch + x * pixelSize; 1296 var pixelPtr = this.getDataPtr(); 1297 var pixelPtrOffset = offset / pixelPtr.BYTES_PER_ELEMENT; 1298 1299 var ub = function(pixel, offset, count) { 1300 return (pixel >> offset) & ((1 << count) - 1); 1301 }; 1302 var nb = function(pixel, offset, count) { 1303 return tcuTexture.channelToNormFloat(ub(pixel, offset, count), count); 1304 }; 1305 1306 // Packed formats. 1307 switch (this.m_format.type) { 1308 case tcuTexture.ChannelType.UNSIGNED_INT_24_8: 1309 switch (this.m_format.order) { 1310 case tcuTexture.ChannelOrder.D: // fall-through 1311 case tcuTexture.ChannelOrder.DS: 1312 return nb(pixelPtr[pixelPtrOffset], 8, 24); 1313 default: 1314 throw new Error('Unsupported tcuTexture.channel order ' + this.m_format.order); 1315 } 1316 break; 1317 1318 case tcuTexture.ChannelType.FLOAT_UNSIGNED_INT_24_8_REV: { 1319 DE_ASSERT(this.m_format.order == tcuTexture.ChannelOrder.DS); 1320 return pixelPtr[pixelPtrOffset]; 1321 break; 1322 } 1323 1324 default: { 1325 DE_ASSERT(this.m_format.order == tcuTexture.ChannelOrder.D || this.m_format.order == tcuTexture.ChannelOrder.DS); 1326 return tcuTexture.channelToFloat(pixelPtr[pixelPtrOffset], this.m_format.type); 1327 } 1328 } 1329 }; 1330 1331 /** 1332 * @param {number} x 1333 * @param {number} y 1334 * @param {number=} z 1335 * @return {Array<number>} Pixel value as Vec4 1336 */ 1337 tcuTexture.ConstPixelBufferAccess.prototype.getPixel = function(x, y, z) { 1338 z = z || 0; 1339 1340 DE_ASSERT(deMath.deInBounds32(x, 0, this.m_width)); 1341 DE_ASSERT(deMath.deInBounds32(y, 0, this.m_height)); 1342 DE_ASSERT(deMath.deInBounds32(z, 0, this.m_depth)); 1343 1344 // Make sure that the position is 'integer' 1345 return this._getPixelInternal(Math.round(x), Math.round(y), Math.round(z)); 1346 }; 1347 1348 // NOTE: getPixel has been broken into getPixel, _getPixelInternal, and _getPixelPacked 1349 // because having them combined previously was causing V8 depots 1350 tcuTexture.ConstPixelBufferAccess.prototype._getPixelInternal = function(x, y, z) { 1351 // Quick paths 1352 if (z == 0) { 1353 if (this.m_rgba8View) { 1354 var color = this.m_rgba8View.read(x, y, 4); 1355 color[0] /= 255; 1356 color[1] /= 255; 1357 color[2] /= 255; 1358 color[3] /= 255; 1359 return color; 1360 } else if (this.m_rgb8View) { 1361 var color = this.m_rgb8View.read(x, y, 3); 1362 color[0] /= 255; 1363 color[1] /= 255; 1364 color[2] /= 255; 1365 color[3] = 1; 1366 return color; 1367 } 1368 } 1369 1370 var pixelSize = this.m_format.getPixelSize(); 1371 var offset = z * this.m_slicePitch + y * this.m_rowPitch + x * pixelSize; 1372 1373 var pixelPtr = this.getDataPtr(); 1374 var pixelPtrOffset = offset / pixelPtr.BYTES_PER_ELEMENT; 1375 1376 return this._getPixelPacked(pixelPtr, pixelPtrOffset); 1377 }; 1378 1379 tcuTexture.ConstPixelBufferAccess.prototype._getPixelPacked = (function() { 1380 1381 var ub = function(pixel, offset, count) { 1382 return (pixel >> offset) & ((1 << count) - 1); 1383 }; 1384 var nb = function(pixel, offset, count) { 1385 var maxVal = (1 << count) - 1; 1386 return ((pixel >> offset) & ((1 << count) - 1)) / maxVal; 1387 }; 1388 var f11 = tcuFloat.float11ToNumber; 1389 var f10 = tcuFloat.float10ToNumber; 1390 1391 return function tcuTexture_ConstPixelBufferAccess_getPixelPacked(pixelPtr, pixelPtrOffset) { 1392 var pixel = pixelPtr[pixelPtrOffset]; 1393 1394 // Packed formats. 1395 switch (this.m_format.type) { 1396 case tcuTexture.ChannelType.UNORM_SHORT_565: return [nb(pixel, 11, 5), nb(pixel, 5, 6), nb(pixel, 0, 5), 1]; 1397 case tcuTexture.ChannelType.UNORM_SHORT_555: return [nb(pixel, 10, 5), nb(pixel, 5, 5), nb(pixel, 0, 5), 1]; 1398 case tcuTexture.ChannelType.UNORM_SHORT_4444: return [nb(pixel, 12, 4), nb(pixel, 8, 4), nb(pixel, 4, 4), nb(pixel, 0, 4)]; 1399 case tcuTexture.ChannelType.UNORM_SHORT_5551: return [nb(pixel, 11, 5), nb(pixel, 6, 5), nb(pixel, 1, 5), nb(pixel, 0, 1)]; 1400 case tcuTexture.ChannelType.UNORM_INT_101010: return [nb(pixel, 22, 10), nb(pixel, 12, 10), nb(pixel, 2, 10), 1]; 1401 case tcuTexture.ChannelType.UNORM_INT_1010102_REV: return [nb(pixel, 0, 10), nb(pixel, 10, 10), nb(pixel, 20, 10), nb(pixel, 30, 2)]; 1402 case tcuTexture.ChannelType.UNSIGNED_INT_1010102_REV: return [ub(pixel, 0, 10), ub(pixel, 10, 10), ub(pixel, 20, 10), ub(pixel, 30, 2)]; 1403 case tcuTexture.ChannelType.UNSIGNED_INT_999_E5_REV: return tcuTexture.unpackRGB999E5(pixel); 1404 1405 case tcuTexture.ChannelType.UNSIGNED_INT_24_8: 1406 switch (this.m_format.order) { 1407 // \note Stencil is always ignored. 1408 case tcuTexture.ChannelOrder.D: return [nb(pixel, 8, 24), 0, 0, 1]; 1409 case tcuTexture.ChannelOrder.DS: return [nb(pixel, 8, 24), 0, 0, 1 /* (float)ub(0, 8) */]; 1410 default: 1411 DE_ASSERT(false); 1412 } 1413 1414 case tcuTexture.ChannelType.FLOAT_UNSIGNED_INT_24_8_REV: { 1415 DE_ASSERT(this.m_format.order == tcuTexture.ChannelOrder.DS); 1416 // \note Stencil is ignored. 1417 return [pixel, 0, 0, 1]; 1418 } 1419 1420 case tcuTexture.ChannelType.UNSIGNED_INT_11F_11F_10F_REV: { 1421 return [f11(ub(pixel, 0, 11)), f11(ub(pixel, 11, 11)), f10(ub(pixel, 22, 10)), 1]; 1422 } 1423 1424 default: 1425 break; 1426 } 1427 1428 // Generic path. 1429 var result = [0, 0, 0, 0]; 1430 var channelMap = tcuTexture.getChannelReadMap(this.m_format.order); 1431 var channelSize = tcuTexture.getChannelSize(this.m_format.type); 1432 1433 for (var c = 0; c < 4; c++) { 1434 var map = channelMap[c]; 1435 if (map == tcuTexture.channel.ZERO) 1436 result[c] = 0; 1437 else if (map == tcuTexture.channel.ONE) 1438 result[c] = 1; 1439 else 1440 result[c] = tcuTexture.channelToFloat(pixelPtr[map + pixelPtrOffset], this.m_format.type); 1441 } 1442 1443 return result; 1444 }; 1445 })(); 1446 1447 /** 1448 * @param {number} x 1449 * @param {number} y 1450 * @param {number=} z 1451 * @return {Array<number>} Pixel value as Vec4 1452 */ 1453 tcuTexture.ConstPixelBufferAccess.prototype.getPixelInt = function(x, y, z) { 1454 z = z || 0; 1455 DE_ASSERT(deMath.deInBounds32(x, 0, this.m_width)); 1456 DE_ASSERT(deMath.deInBounds32(y, 0, this.m_height)); 1457 DE_ASSERT(deMath.deInBounds32(z, 0, this.m_depth)); 1458 1459 // Make sure that the position is 'integer' 1460 x = Math.round(x); 1461 y = Math.round(y); 1462 z = Math.round(z); 1463 1464 // Quick paths 1465 if (z == 0) { 1466 if (this.m_rgba8View) 1467 return this.m_rgba8View.read(x, y, 4); 1468 else if (this.m_rgb8View) 1469 return this.m_rgb8View.read(x, y, 3); 1470 } 1471 1472 var pixelSize = this.m_format.getPixelSize(); 1473 var offset = z * this.m_slicePitch + y * this.m_rowPitch + x * pixelSize; 1474 1475 var pixelPtr = this.getDataPtr(); 1476 var pixelPtrOffset = offset / pixelPtr.BYTES_PER_ELEMENT; 1477 var pixel = pixelPtr[pixelPtrOffset]; 1478 1479 var ub = function(pixel, offset, count) { 1480 return (pixel >> offset) & ((1 << count) - 1); 1481 }; 1482 1483 // Packed formats. 1484 switch (this.m_format.type) { 1485 case tcuTexture.ChannelType.UNORM_SHORT_565: return [ub(pixel, 11, 5), ub(pixel, 5, 6), ub(pixel, 0, 5), 1]; 1486 case tcuTexture.ChannelType.UNORM_SHORT_555: return [ub(pixel, 10, 5), ub(pixel, 5, 5), ub(pixel, 0, 5), 1]; 1487 case tcuTexture.ChannelType.UNORM_SHORT_4444: return [ub(pixel, 12, 4), ub(pixel, 8, 4), ub(pixel, 4, 4), ub(pixel, 0, 4)]; 1488 case tcuTexture.ChannelType.UNORM_SHORT_5551: return [ub(pixel, 11, 5), ub(pixel, 6, 5), ub(pixel, 1, 5), ub(pixel, 0, 1)]; 1489 case tcuTexture.ChannelType.UNORM_INT_101010: return [ub(pixel, 22, 10), ub(pixel, 12, 10), ub(pixel, 2, 10), 1]; 1490 case tcuTexture.ChannelType.UNORM_INT_1010102_REV: return [ub(pixel, 0, 10), ub(pixel, 10, 10), ub(pixel, 20, 10), ub(pixel, 30, 2)]; 1491 case tcuTexture.ChannelType.UNSIGNED_INT_1010102_REV: return [ub(pixel, 0, 10), ub(pixel, 10, 10), ub(pixel, 20, 10), ub(pixel, 30, 2)]; 1492 1493 case tcuTexture.ChannelType.UNSIGNED_INT_24_8: 1494 switch (this.m_format.order) { 1495 case tcuTexture.ChannelOrder.D: return [ub(pixel, 8, 24), 0, 0, 1]; 1496 case tcuTexture.ChannelOrder.S: return [0, 0, 0, ub(pixel, 8, 24)]; 1497 case tcuTexture.ChannelOrder.DS: return [ub(pixel, 8, 24), 0, 0, ub(pixel, 0, 8)]; 1498 default: 1499 DE_ASSERT(false); 1500 } 1501 1502 case tcuTexture.ChannelType.FLOAT_UNSIGNED_INT_24_8_REV: { 1503 DE_ASSERT(this.m_format.order == tcuTexture.ChannelOrder.DS); 1504 var u32array = new Uint32Array(this.m_data, this.m_offset + offset + 4, 1); 1505 return [pixel, 0, 0, ub(u32array[0], 0, 8)]; 1506 } 1507 1508 default: 1509 break; 1510 } 1511 1512 // Generic path. 1513 var result = []; 1514 result.length = 4; 1515 var channelMap = tcuTexture.getChannelReadMap(this.m_format.order); 1516 var channelSize = tcuTexture.getChannelSize(this.m_format.type); 1517 1518 for (var c = 0; c < 4; c++) { 1519 var map = channelMap[c]; 1520 if (map == tcuTexture.channel.ZERO) 1521 result[c] = 0; 1522 else if (map == tcuTexture.channel.ONE) 1523 result[c] = 1; 1524 else 1525 result[c] = tcuTexture.channelToInt(pixelPtr[map + pixelPtrOffset], this.m_format.type); 1526 } 1527 1528 return result; 1529 }; 1530 1531 /** 1532 * @param {tcuTexture.Sampler} sampler 1533 * @param {?tcuTexture.FilterMode} filter 1534 * @param {number} s 1535 * @param {number} t 1536 * @param {number} depth (integer) 1537 * @return {Array<number>} Sample color 1538 */ 1539 tcuTexture.ConstPixelBufferAccess.prototype.sample2D = function(sampler, filter, s, t, depth) { 1540 DE_ASSERT(deMath.deInBounds32(depth, 0, this.m_depth)); 1541 1542 // Non-normalized coordinates. 1543 var u = s; 1544 var v = t; 1545 1546 if (sampler.normalizedCoords) { 1547 u = tcuTexture.unnormalize(sampler.wrapS, s, this.m_width); 1548 v = tcuTexture.unnormalize(sampler.wrapT, t, this.m_height); 1549 } 1550 1551 switch (filter) { 1552 case tcuTexture.FilterMode.NEAREST: return tcuTexture.sampleNearest2D(this, sampler, u, v, depth); 1553 case tcuTexture.FilterMode.LINEAR: return tcuTexture.sampleLinear2D(this, sampler, u, v, depth); 1554 default: 1555 throw new Error('Invalid filter:' + filter); 1556 } 1557 throw new Error('Unimplemented'); 1558 }; 1559 1560 /** 1561 * @param {tcuTexture.Sampler} sampler 1562 * @param {?tcuTexture.FilterMode} filter 1563 * @param {number} s 1564 * @param {number} t 1565 * @param {Array<number>} offset 1566 * @return {Array<number>} Sample color 1567 */ 1568 tcuTexture.ConstPixelBufferAccess.prototype.sample2DOffset = function(sampler, filter, s, t, offset) { 1569 DE_ASSERT(deMath.deInBounds32(offset[2], 0, this.m_depth)); 1570 1571 // Non-normalized coordinates. 1572 var u = s; 1573 var v = t; 1574 1575 if (sampler.normalizedCoords) { 1576 u = tcuTexture.unnormalize(sampler.wrapS, s, this.m_width); 1577 v = tcuTexture.unnormalize(sampler.wrapT, t, this.m_height); 1578 } 1579 1580 switch (filter) { 1581 case tcuTexture.FilterMode.NEAREST: return tcuTexture.sampleNearest2D(this, sampler, u, v, offset); 1582 case tcuTexture.FilterMode.LINEAR: return tcuTexture.sampleLinear2D(this, sampler, u, v, offset); 1583 default: 1584 throw new Error('Invalid filter:' + filter); 1585 } 1586 }; 1587 1588 /** 1589 * @param {tcuTexture.Sampler} sampler 1590 * @param {?tcuTexture.FilterMode} filter 1591 * @param {number} s 1592 * @param {number} t 1593 * @param {number} r 1594 * @param {Array<number>} offset 1595 * @return {Array<number>} Sample color 1596 */ 1597 tcuTexture.ConstPixelBufferAccess.prototype.sample3DOffset = function(sampler, filter, s, t, r, offset) { 1598 // Non-normalized coordinates. 1599 /** @type {number} */ var u = s; 1600 /** @type {number} */ var v = t; 1601 /** @type {number} */ var w = r; 1602 1603 if (sampler.normalizedCoords) { 1604 u = tcuTexture.unnormalize(sampler.wrapS, s, this.m_width); 1605 v = tcuTexture.unnormalize(sampler.wrapT, t, this.m_height); 1606 w = tcuTexture.unnormalize(sampler.wrapR, r, this.m_depth); 1607 } 1608 1609 switch (filter) { 1610 case tcuTexture.FilterMode.NEAREST: return tcuTexture.sampleNearest3D(this, sampler, u, v, w, offset); 1611 case tcuTexture.FilterMode.LINEAR: return tcuTexture.sampleLinear3D(this, sampler, u, v, w, offset); 1612 default: 1613 throw new Error('Invalid filter:' + filter); 1614 } 1615 }; 1616 1617 /** 1618 * @param {tcuTexture.Sampler} sampler 1619 * @param {tcuTexture.FilterMode} filter 1620 * @param {number} ref 1621 * @param {number} s 1622 * @param {number} t 1623 * @param {Array<number>} offset 1624 * @return {number} 1625 */ 1626 tcuTexture.ConstPixelBufferAccess.prototype.sample2DCompare = function(sampler, filter, ref, s, t, offset) { 1627 DE_ASSERT(deMath.deInBounds32(offset[2], 0, this.m_depth)); 1628 1629 // Format information for comparison function 1630 var isFixedPointDepth = tcuTexture.isFixedPointDepthTextureFormat(this.m_format); 1631 1632 // Non-normalized coordinates. 1633 var u = s; 1634 var v = t; 1635 1636 if (sampler.normalizedCoords) { 1637 u = tcuTexture.unnormalize(sampler.wrapS, s, this.m_width); 1638 v = tcuTexture.unnormalize(sampler.wrapT, t, this.m_height); 1639 } 1640 1641 switch (filter) { 1642 case tcuTexture.FilterMode.NEAREST: return tcuTexture.execCompare(tcuTexture.sampleNearest2D(this, sampler, u, v, offset), sampler.compare, sampler.compareChannel, ref, isFixedPointDepth); 1643 case tcuTexture.FilterMode.LINEAR: return tcuTexture.sampleLinear2DCompare(this, sampler, ref, u, v, offset, isFixedPointDepth); 1644 default: 1645 DE_ASSERT(false); 1646 return 0.0; 1647 } 1648 }; 1649 1650 /** 1651 * @param {tcuTexture.Sampler} sampler 1652 * @param {tcuTexture.FilterMode} filter 1653 * @param {number} s 1654 * @param {number} t 1655 * @param {number} r 1656 * @return {Array<number>} Sample color 1657 */ 1658 tcuTexture.ConstPixelBufferAccess.prototype.sample3D = function(sampler, filter, s, t, r) { 1659 // Non-normalized coordinates. 1660 var u = s; 1661 var v = t; 1662 var w = r; 1663 1664 if (sampler.normalizedCoords) { 1665 u = tcuTexture.unnormalize(sampler.wrapS, s, this.m_width); 1666 v = tcuTexture.unnormalize(sampler.wrapT, t, this.m_height); 1667 w = tcuTexture.unnormalize(sampler.wrapR, r, this.m_depth); 1668 } 1669 1670 switch (filter) { 1671 case tcuTexture.FilterMode.NEAREST: return tcuTexture.sampleNearest3D(this, sampler, u, v, w); 1672 case tcuTexture.FilterMode.LINEAR: return tcuTexture.sampleLinear3D(this, sampler, u, v, w); 1673 default: 1674 throw new Error('Invalid filter:' + filter); 1675 } 1676 throw new Error('Unimplemented'); 1677 }; 1678 1679 /* TODO: do we need any of these? */ { 1680 // template<typename T> 1681 // Vector<T, 4> getPixelT (int x, int y, int z = 0) const; 1682 1683 // Vec4 sample3D (const tcuTexture.Sampler& sampler, tcuTexture.tcuTexture.Sampler.tcuTexture.FilterMode filter, float s, float t, float r) const; 1684 1685 // Vec4 sample2DOffset (const tcuTexture.Sampler& sampler, tcuTexture.Sampler::tcuTexture.FilterMode filter, float s, float t, const IVec3& offset) const; 1686 // Vec4 sample3DOffset (const tcuTexture.Sampler& sampler, tcuTexture.Sampler::tcuTexture.FilterMode filter, float s, float t, float r, const IVec3& offset) const; 1687 1688 // float sample2DCompare (const tcuTexture.Sampler& sampler, tcuTexture.Sampler::tcuTexture.FilterMode filter, float ref, float s, float t, const IVec3& offset) const; 1689 }; 1690 1691 /** Common type limits 1692 * 1693 */ 1694 tcuTexture.deTypes = { 1695 deInt8: {min: -(1 << 7), max: (1 << 7) - 1}, 1696 deInt16: {min: -(1 << 15), max: (1 << 15) - 1}, 1697 deInt32: {min: -2147483648, max: 2147483647}, 1698 deUint8: {min: 0, max: (1 << 8) - 1}, 1699 deUint16: {min: 0, max: (1 << 16) - 1}, 1700 deUint32: {min: 0, max: 4294967295} 1701 }; 1702 1703 /** 1704 * Round to even and saturate 1705 * @param {{max: number, min: number}} deType from tcuTexture.deTypes 1706 * @param {number} value 1707 * @return {number} 1708 */ 1709 tcuTexture.convertSatRte = function(deType, value) { 1710 var minVal = deType.min; 1711 var maxVal = deType.max; 1712 var floor = Math.floor(value); 1713 var frac = value - floor; 1714 if (frac == 0.5) { 1715 if (floor % 2 != 0) 1716 floor += 1; 1717 } else if (frac > 0.5) { 1718 floor += 1; 1719 } 1720 1721 return Math.max(minVal, Math.min(maxVal, floor)); 1722 }; 1723 1724 /** 1725 * Saturate value to type range 1726 * @param { {max: number, min: number}} deType from tcuTexture.deTypes 1727 * @param {number} src 1728 * @return {number} 1729 */ 1730 tcuTexture.convertSat = function(deType, src) { 1731 var minVal = deType.min; 1732 var maxVal = deType.max; 1733 if (src < minVal) 1734 return minVal; 1735 else if (src > maxVal) 1736 return maxVal; 1737 else 1738 return src; 1739 }; 1740 1741 /** 1742 * @param {number} src Input integer value 1743 * @param {tcuTexture.ChannelType} type 1744 * @return {number} 1745 */ 1746 tcuTexture.intToChannel = function(src, type) { 1747 var dst; 1748 switch (type) { 1749 case tcuTexture.ChannelType.SNORM_INT8: dst = tcuTexture.convertSat(tcuTexture.deTypes.deInt8, src); break; 1750 case tcuTexture.ChannelType.SNORM_INT16: dst = tcuTexture.convertSat(tcuTexture.deTypes.deInt16, src); break; 1751 case tcuTexture.ChannelType.UNORM_INT8: dst = tcuTexture.convertSat(tcuTexture.deTypes.deUint8, src); break; 1752 case tcuTexture.ChannelType.UNORM_INT16: dst = tcuTexture.convertSat(tcuTexture.deTypes.deUint16, src); break; 1753 case tcuTexture.ChannelType.SIGNED_INT8: dst = tcuTexture.convertSat(tcuTexture.deTypes.deInt8, src); break; 1754 case tcuTexture.ChannelType.SIGNED_INT16: dst = tcuTexture.convertSat(tcuTexture.deTypes.deInt16, src); break; 1755 case tcuTexture.ChannelType.SIGNED_INT32: dst = tcuTexture.convertSat(tcuTexture.deTypes.deInt32, src); break; 1756 case tcuTexture.ChannelType.UNSIGNED_INT8: dst = tcuTexture.convertSat(tcuTexture.deTypes.deUint8, src); break; 1757 case tcuTexture.ChannelType.UNSIGNED_INT16: dst = tcuTexture.convertSat(tcuTexture.deTypes.deUint16, src); break; 1758 case tcuTexture.ChannelType.UNSIGNED_INT32: dst = tcuTexture.convertSat(tcuTexture.deTypes.deUint32, src); break; 1759 case tcuTexture.ChannelType.HALF_FLOAT: dst = tcuFloat.numberToHalfFloat(src); break; 1760 case tcuTexture.ChannelType.FLOAT: dst = src; break; 1761 default: 1762 throw new Error('Unrecognized tcuTexture.channel type: ' + type); 1763 } 1764 return dst; 1765 }; 1766 1767 /** 1768 * @param {number} src 1769 * @param {number} bits 1770 * @return {number} 1771 */ 1772 tcuTexture.normFloatToChannel = function(src, bits) { 1773 var maxVal = (1 << bits) - 1; 1774 var intVal = tcuTexture.convertSatRte(tcuTexture.deTypes.deUint32, src * maxVal); 1775 return Math.min(maxVal, intVal); 1776 }; 1777 1778 /** 1779 * @param {number} src 1780 * @param {number} bits 1781 * @return {number} 1782 */ 1783 tcuTexture.uintToChannel = function(src, bits) { 1784 var maxVal = (1 << bits) - 1; 1785 return Math.min(maxVal, src); 1786 }; 1787 1788 /** 1789 * @param {number} src 1790 * @param {tcuTexture.ChannelType} type 1791 * @return {number} Converted src color value 1792 */ 1793 tcuTexture.floatToChannel = function(src, type) { 1794 switch (type) { 1795 case tcuTexture.ChannelType.SNORM_INT8: return tcuTexture.convertSatRte(tcuTexture.deTypes.deInt8, src * 127); 1796 case tcuTexture.ChannelType.SNORM_INT16: return tcuTexture.convertSatRte(tcuTexture.deTypes.deInt16, src * 32767); 1797 case tcuTexture.ChannelType.SNORM_INT32: return tcuTexture.convertSatRte(tcuTexture.deTypes.deInt32, src * 2147483647); 1798 case tcuTexture.ChannelType.UNORM_INT8: return tcuTexture.convertSatRte(tcuTexture.deTypes.deUint8, src * 255); 1799 case tcuTexture.ChannelType.UNORM_INT16: return tcuTexture.convertSatRte(tcuTexture.deTypes.deUint16, src * 65535); 1800 case tcuTexture.ChannelType.UNORM_INT32: return tcuTexture.convertSatRte(tcuTexture.deTypes.deUint32, src * 4294967295); 1801 case tcuTexture.ChannelType.SIGNED_INT8: return tcuTexture.convertSatRte(tcuTexture.deTypes.deInt8, src); 1802 case tcuTexture.ChannelType.SIGNED_INT16: return tcuTexture.convertSatRte(tcuTexture.deTypes.deInt16, src); 1803 case tcuTexture.ChannelType.SIGNED_INT32: return tcuTexture.convertSatRte(tcuTexture.deTypes.deInt32, src); 1804 case tcuTexture.ChannelType.UNSIGNED_INT8: return tcuTexture.convertSatRte(tcuTexture.deTypes.deUint8, src); 1805 case tcuTexture.ChannelType.UNSIGNED_INT16: return tcuTexture.convertSatRte(tcuTexture.deTypes.deUint16, src); 1806 case tcuTexture.ChannelType.UNSIGNED_INT32: return tcuTexture.convertSatRte(tcuTexture.deTypes.deUint32, src); 1807 case tcuTexture.ChannelType.HALF_FLOAT: return tcuFloat.numberToHalfFloat(src); 1808 case tcuTexture.ChannelType.FLOAT: return src; 1809 } 1810 throw new Error('Unrecognized type ' + type); 1811 }; 1812 1813 /** 1814 * \brief Read-write pixel data access 1815 * 1816 * This class extends read-only access object by providing write functionality. 1817 * 1818 * \note tcuTexture.PixelBufferAccess may not have any data members nor add any 1819 * virtual functions. It must be possible to reinterpret_cast<> 1820 * tcuTexture.PixelBufferAccess to tcuTexture.ConstPixelBufferAccess. 1821 * @constructor 1822 * @extends {tcuTexture.ConstPixelBufferAccess} 1823 * 1824 */ 1825 tcuTexture.PixelBufferAccess = function(descriptor) { 1826 tcuTexture.ConstPixelBufferAccess.call(this, descriptor); 1827 }; 1828 1829 tcuTexture.PixelBufferAccess.prototype = Object.create(tcuTexture.ConstPixelBufferAccess.prototype); 1830 tcuTexture.PixelBufferAccess.prototype.constructor = tcuTexture.PixelBufferAccess; 1831 1832 /** 1833 * @param {Array<number>} color Vec4 color to set 1834 * @param {number} x 1835 * @param {number} y 1836 * @param {number=} z 1837 */ 1838 tcuTexture.PixelBufferAccess.prototype.setPixel = function(color, x, y, z) { 1839 z = z || 0; 1840 DE_ASSERT(deMath.deInBounds32(x, 0, this.m_width)); 1841 DE_ASSERT(deMath.deInBounds32(y, 0, this.m_height)); 1842 DE_ASSERT(deMath.deInBounds32(z, 0, this.m_depth)); 1843 1844 // Make sure that the position is 'integer' 1845 this._setPixelInternal(color, Math.round(x), Math.round(y), Math.round(z)); 1846 }; 1847 1848 // NOTE: setPixel has been broken into setPixel, _setPixelInternal, and _setPixelPacked 1849 // because having them combined previously was causing V8 depots 1850 tcuTexture.PixelBufferAccess.prototype._setPixelInternal = function(color, x, y, z) { 1851 // Quick paths 1852 if (z == 0) { 1853 if (this.m_rgba8View) { 1854 color = deMath.toIVec(color); 1855 this.m_rgba8View.write(x, y, color, 4); 1856 return; 1857 } else if (this.m_rgb8View) { 1858 color = deMath.toIVec(color); 1859 this.m_rgb8View.write(x, y, color, 3); 1860 return; 1861 } 1862 } 1863 1864 var pixelSize = this.m_format.getPixelSize(); 1865 var offset = z * this.m_slicePitch + y * this.m_rowPitch + x * pixelSize; 1866 var pixelPtr = this.getDataPtr(); 1867 var pixelPtrOffset = offset / pixelPtr.BYTES_PER_ELEMENT; 1868 1869 return this._setPixelPacked(color, pixelPtr, pixelPtrOffset); 1870 }; 1871 1872 tcuTexture.PixelBufferAccess.prototype._setPixelPacked = (function () { 1873 var pn = function(val, offs, bits) { 1874 return tcuTexture.normFloatToChannel(val, bits) << offs; 1875 }; 1876 1877 var pu = function(val, offs, bits) { 1878 return tcuTexture.uintToChannel(val, bits) << offs; 1879 }; 1880 1881 return function tcuTexture_PixelBufferAccess_setPixelPacked(color, pixelPtr, pixelPtrOffset) { 1882 // Packed formats. 1883 switch (this.m_format.type) { 1884 case tcuTexture.ChannelType.UNORM_SHORT_565: pixelPtr[pixelPtrOffset] = pn(color[0], 11, 5) | pn(color[1], 5, 6) | pn(color[2], 0, 5); break; 1885 case tcuTexture.ChannelType.UNORM_SHORT_555: pixelPtr[pixelPtrOffset] = pn(color[0], 10, 5) | pn(color[1], 5, 5) | pn(color[2], 0, 5); break; 1886 case tcuTexture.ChannelType.UNORM_SHORT_4444: pixelPtr[pixelPtrOffset] = pn(color[0], 12, 4) | pn(color[1], 8, 4) | pn(color[2], 4, 4) | pn(color[3], 0, 4); break; 1887 case tcuTexture.ChannelType.UNORM_SHORT_5551: pixelPtr[pixelPtrOffset] = pn(color[0], 11, 5) | pn(color[1], 6, 5) | pn(color[2], 1, 5) | pn(color[3], 0, 1); break; 1888 case tcuTexture.ChannelType.UNORM_INT_101010: pixelPtr[pixelPtrOffset] = pn(color[0], 22, 10) | pn(color[1], 12, 10) | pn(color[2], 2, 10); break; 1889 case tcuTexture.ChannelType.UNORM_INT_1010102_REV: pixelPtr[pixelPtrOffset] = pn(color[0], 0, 10) | pn(color[1], 10, 10) | pn(color[2], 20, 10) | pn(color[3], 30, 2); break; 1890 case tcuTexture.ChannelType.UNSIGNED_INT_1010102_REV: pixelPtr[pixelPtrOffset] = pu(color[0], 0, 10) | pu(color[1], 10, 10) | pu(color[2], 20, 10) | pu(color[3], 30, 2); break; 1891 case tcuTexture.ChannelType.UNSIGNED_INT_999_E5_REV: pixelPtr[pixelPtrOffset] = tcuTexture.packRGB999E5(color); break; 1892 1893 case tcuTexture.ChannelType.UNSIGNED_INT_24_8: 1894 switch (this.m_format.order) { 1895 // \note Stencil is always ignored. 1896 case tcuTexture.ChannelOrder.D: pixelPtr[pixelPtrOffset] = pn(color[0], 8, 24); break; 1897 case tcuTexture.ChannelOrder.S: pixelPtr[pixelPtrOffset] = pn(color[3], 8, 24); break; 1898 case tcuTexture.ChannelOrder.DS: pixelPtr[pixelPtrOffset] = pn(color[0], 8, 24) | pu(color[3], 0, 8); break; 1899 default: 1900 throw new Error('Unsupported tcuTexture.channel order ' + this.m_format.order); 1901 } 1902 break; 1903 1904 case tcuTexture.ChannelType.FLOAT_UNSIGNED_INT_24_8_REV: { 1905 pixelPtr[pixelPtrOffset] = color[0]; 1906 var u32array = new Uint32Array(this.m_data, (pixelPtrOffset * pixelPtr.BYTES_PER_ELEMENT) + this.m_offset + 4, 1); 1907 u32array[0] = pu(color[3], 0, 8); 1908 break; 1909 } 1910 1911 case tcuTexture.ChannelType.UNSIGNED_INT_11F_11F_10F_REV: { 1912 var f11 = function(value) { 1913 return tcuFloat.numberToFloat11(value); 1914 }; 1915 var f10 = function(value) { 1916 return tcuFloat.numberToFloat10(value); 1917 }; 1918 1919 pixelPtr[pixelPtrOffset] = f11(color[0]) | (f11(color[1]) << 11) | (f10(color[2]) << 22); 1920 break; 1921 } 1922 case tcuTexture.ChannelType.FLOAT: 1923 if (this.m_format.order == tcuTexture.ChannelOrder.D) { 1924 pixelPtr[pixelPtrOffset] = color[0]; 1925 break; 1926 } 1927 // else fall-through to default case! 1928 1929 default: { 1930 // Generic path. 1931 var numChannels = tcuTexture.getNumUsedChannels(this.m_format.order); 1932 var map = tcuTexture.getChannelWriteMap(this.m_format.order); 1933 1934 for (var c = 0; c < numChannels; c++) 1935 pixelPtr[c + pixelPtrOffset] = tcuTexture.floatToChannel(color[map[c]], this.m_format.type); 1936 } 1937 } 1938 }; 1939 })(); 1940 1941 /** 1942 * @param {Array<number>} color Vec4 color to set (unnormalized) 1943 * @param {number} x 1944 * @param {number} y 1945 * @param {number=} z 1946 */ 1947 tcuTexture.PixelBufferAccess.prototype.setPixelInt = function(color, x, y, z) { 1948 z = z || 0; 1949 DE_ASSERT(deMath.deInBounds32(x, 0, this.m_width)); 1950 DE_ASSERT(deMath.deInBounds32(y, 0, this.m_height)); 1951 DE_ASSERT(deMath.deInBounds32(z, 0, this.m_depth)); 1952 1953 // Make sure that the position is 'integer' 1954 x = Math.round(x); 1955 y = Math.round(y); 1956 z = Math.round(z); 1957 1958 // Quick paths 1959 if (z == 0) { 1960 if (this.m_rgba8View) { 1961 this.m_rgba8View.write(x, y, color, 4); 1962 return; 1963 } else if (this.m_rgb8View) { 1964 this.m_rgb8View.write(x, y, color, 3); 1965 return; 1966 } 1967 } 1968 1969 var pixelSize = this.m_format.getPixelSize(); 1970 var offset = z * this.m_slicePitch + y * this.m_rowPitch + x * pixelSize; 1971 var pixelPtr = this.getDataPtr(); 1972 var pixelPtrOffset = offset / pixelPtr.BYTES_PER_ELEMENT; 1973 1974 var pu = function(val, offs, bits) { 1975 return tcuTexture.uintToChannel(val, bits) << offs; 1976 }; 1977 1978 // Packed formats. 1979 switch (this.m_format.type) { 1980 case tcuTexture.ChannelType.UNORM_SHORT_565: pixelPtr[pixelPtrOffset] = pu(color[0], 11, 5) | pu(color[1], 5, 6) | pu(color[2], 0, 5); break; 1981 case tcuTexture.ChannelType.UNORM_SHORT_555: pixelPtr[pixelPtrOffset] = pu(color[0], 10, 5) | pu(color[1], 5, 5) | pu(color[2], 0, 5); break; 1982 case tcuTexture.ChannelType.UNORM_SHORT_4444: pixelPtr[pixelPtrOffset] = pu(color[0], 12, 4) | pu(color[1], 8, 4) | pu(color[2], 4, 4) | pu(color[3], 0, 4); break; 1983 case tcuTexture.ChannelType.UNORM_SHORT_5551: pixelPtr[pixelPtrOffset] = pu(color[0], 11, 5) | pu(color[1], 6, 5) | pu(color[2], 1, 5) | pu(color[3], 0, 1); break; 1984 case tcuTexture.ChannelType.UNORM_INT_101010: pixelPtr[pixelPtrOffset] = pu(color[0], 22, 10) | pu(color[1], 12, 10) | pu(color[2], 2, 10); break; 1985 case tcuTexture.ChannelType.UNORM_INT_1010102_REV: pixelPtr[pixelPtrOffset] = pu(color[0], 0, 10) | pu(color[1], 10, 10) | pu(color[2], 20, 10) | pu(color[3], 30, 2); break; 1986 case tcuTexture.ChannelType.UNSIGNED_INT_1010102_REV: pixelPtr[pixelPtrOffset] = pu(color[0], 0, 10) | pu(color[1], 10, 10) | pu(color[2], 20, 10) | pu(color[3], 30, 2); break; 1987 1988 case tcuTexture.ChannelType.UNSIGNED_INT_24_8: 1989 switch (this.m_format.order) { 1990 // \note Stencil is always ignored. 1991 case tcuTexture.ChannelOrder.D: pixelPtr[pixelPtrOffset] = pu(color[0], 8, 24); break; 1992 case tcuTexture.ChannelOrder.S: pixelPtr[pixelPtrOffset] = pu(color[3], 8, 24); break; 1993 case tcuTexture.ChannelOrder.DS: pixelPtr[pixelPtrOffset] = pu(color[0], 8, 24) | pu(color[3], 0, 8); break; 1994 default: 1995 throw new Error('Unsupported tcuTexture.channel order ' + this.m_format.order); 1996 } 1997 break; 1998 1999 case tcuTexture.ChannelType.FLOAT_UNSIGNED_INT_24_8_REV: { 2000 pixelPtr[pixelPtrOffset] = color[0]; 2001 var u32array = new Uint32Array(this.m_data, offset + this.m_offset + 4, 1); 2002 u32array[pixelPtrOffset] = pu(color[3], 0, 8); 2003 break; 2004 } 2005 2006 default: { 2007 // Generic path. 2008 var numChannels = tcuTexture.getNumUsedChannels(this.m_format.order); 2009 var map = tcuTexture.getChannelWriteMap(this.m_format.order); 2010 2011 for (var c = 0; c < numChannels; c++) 2012 pixelPtr[c + pixelPtrOffset] = tcuTexture.intToChannel(color[map[c]], this.m_format.type); 2013 } 2014 } 2015 }; 2016 2017 /** 2018 * @param {Array<number>=} color Vec4 color to set, optional. 2019 * @param {Array<number>=} x Range in x axis, optional. 2020 * @param {Array<number>=} y Range in y axis, optional. 2021 * @param {Array<number>=} z Range in z axis, optional. 2022 */ 2023 tcuTexture.PixelBufferAccess.prototype.clear = function(color, x, y, z) { 2024 var c = color || [0, 0, 0, 0]; 2025 var arrayType = tcuTexture.getTypedArray(this.m_format.type); 2026 var range_x = x || [0, this.m_width]; 2027 var range_y = y || [0, this.m_height]; 2028 var range_z = z || [0, this.m_depth]; 2029 var pixelSize = this.m_format.getPixelSize(); 2030 var numElements = pixelSize / arrayType.BYTES_PER_ELEMENT; 2031 var width = range_x[1] - range_x[0]; 2032 var height = range_y[1] - range_y[0]; 2033 var depth = range_z[1] - range_z[0]; 2034 if (x === undefined && y === undefined && z === undefined && 2035 c[0] == 0 && c[1] == 0 && c[2] == 0 && c[3] == 0) { 2036 var pixelPtr = new arrayType(this.m_data, this.m_offset); 2037 pixelPtr.fill(0); 2038 return; 2039 } 2040 2041 //copy first pixel over other pixels in the row 2042 var fillRow = function(pixelPtr, numElements, width) { 2043 for (var i = 1; i < width; i++) 2044 for (var c = 0; c < numElements; c++) 2045 pixelPtr[i * numElements + c] = pixelPtr[c]; 2046 }; 2047 // copy first row to other rows in all planes 2048 var fillPlanes = function(buffer, arrayType, src, offset, rowStride, planeStride, width, height, depth) { 2049 for (var j = 0; j < depth; j++) 2050 for (var i = (j == 0 ? 1 : 0); i < height; i++) { 2051 var dst = new arrayType(buffer, offset + i * rowStride + j * planeStride, width); 2052 dst.set(src); 2053 } 2054 }; 2055 2056 this.setPixel(c, range_x[0], range_y[0], range_z[0]); 2057 2058 var offset = range_z[0] * this.m_slicePitch + range_y[0] * this.m_rowPitch + range_x[0] * pixelSize; 2059 var pixelPtr = new arrayType(this.m_data, offset + this.m_offset, width * numElements); 2060 2061 fillRow(pixelPtr, numElements, width); 2062 fillPlanes(this.m_data, arrayType, pixelPtr, offset + this.m_offset, this.m_rowPitch, this.m_slicePitch, width * numElements, height, depth); 2063 }; 2064 2065 /** 2066 * @param {number} depth to set 2067 * @param {number} x 2068 * @param {number} y 2069 * @param {number=} z 2070 */ 2071 tcuTexture.PixelBufferAccess.prototype.setPixDepth = function(depth, x, y, z) { 2072 if (z == null) 2073 z = 0; 2074 DE_ASSERT(deMath.deInBounds32(x, 0, this.m_width)); 2075 DE_ASSERT(deMath.deInBounds32(y, 0, this.m_height)); 2076 DE_ASSERT(deMath.deInBounds32(z, 0, this.m_depth)); 2077 2078 // Make sure that the position is 'integer' 2079 x = Math.round(x); 2080 y = Math.round(y); 2081 z = Math.round(z); 2082 2083 var pixelSize = this.m_format.getPixelSize(); 2084 var offset = z * this.m_slicePitch + y * this.m_rowPitch + x * pixelSize; 2085 var pixelPtr = this.getDataPtr(); 2086 var pixelPtrOffset = offset / pixelPtr.BYTES_PER_ELEMENT; 2087 2088 var pn = function(val, offs, bits) { 2089 return tcuTexture.normFloatToChannel(val, bits) << offs; 2090 }; 2091 2092 // Packed formats. 2093 switch (this.m_format.type) { 2094 case tcuTexture.ChannelType.UNSIGNED_INT_24_8: 2095 switch (this.m_format.order) { 2096 case tcuTexture.ChannelOrder.D: pixelPtr[pixelPtrOffset] = pn(depth, 8, 24); break; 2097 case tcuTexture.ChannelOrder.DS: pixelPtr[pixelPtrOffset] = pn(depth, 8, 24) | (pixelPtr[pixelPtrOffset] & 0xFF); break; 2098 default: 2099 throw new Error('Unsupported tcuTexture.channel order ' + this.m_format.order); 2100 } 2101 break; 2102 2103 case tcuTexture.ChannelType.FLOAT_UNSIGNED_INT_24_8_REV: { 2104 DE_ASSERT(this.m_format.order == tcuTexture.ChannelOrder.DS); 2105 pixelPtr[pixelPtrOffset] = depth; 2106 break; 2107 } 2108 2109 default: { 2110 DE_ASSERT(this.m_format.order == tcuTexture.ChannelOrder.D || this.m_format.order == tcuTexture.ChannelOrder.DS); 2111 pixelPtr[pixelPtrOffset] = tcuTexture.floatToChannel(depth, this.m_format.type); 2112 } 2113 } 2114 }; 2115 2116 /** 2117 * @param {number} stencil to set 2118 * @param {number} x 2119 * @param {number} y 2120 * @param {number=} z 2121 */ 2122 tcuTexture.PixelBufferAccess.prototype.setPixStencil = function(stencil, x, y, z) { 2123 if (z == null) 2124 z = 0; 2125 DE_ASSERT(deMath.deInBounds32(x, 0, this.m_width)); 2126 DE_ASSERT(deMath.deInBounds32(y, 0, this.m_height)); 2127 DE_ASSERT(deMath.deInBounds32(z, 0, this.m_depth)); 2128 2129 // Make sure that the position is 'integer' 2130 x = Math.round(x); 2131 y = Math.round(y); 2132 z = Math.round(z); 2133 2134 var pixelSize = this.m_format.getPixelSize(); 2135 var offset = z * this.m_slicePitch + y * this.m_rowPitch + x * pixelSize; 2136 var pixelPtr = this.getDataPtr(); 2137 var pixelPtrOffset = offset / pixelPtr.BYTES_PER_ELEMENT; 2138 2139 var pu = function(val, offs, bits) { 2140 return tcuTexture.uintToChannel(val, bits) << offs; 2141 }; 2142 2143 // Packed formats. 2144 switch (this.m_format.type) { 2145 case tcuTexture.ChannelType.UNSIGNED_INT_24_8: 2146 switch (this.m_format.order) { 2147 case tcuTexture.ChannelOrder.S: pixelPtr[pixelPtrOffset] = pu(stencil, 8, 24); break; 2148 case tcuTexture.ChannelOrder.DS: pixelPtr[pixelPtrOffset] = pu(stencil, 0, 8) | (pixelPtr[pixelPtrOffset] & 0xFFFFFF00); break; 2149 default: 2150 throw new Error('Unsupported tcuTexture.channel order ' + this.m_format.order); 2151 } 2152 break; 2153 2154 case tcuTexture.ChannelType.FLOAT_UNSIGNED_INT_24_8_REV: { 2155 var u32array = new Uint32Array(this.m_data, this.m_offset + offset + 4, 1); 2156 u32array[0] = pu(stencil, 0, 8); 2157 break; 2158 } 2159 2160 default: { 2161 if (this.m_format.order == tcuTexture.ChannelOrder.S) 2162 pixelPtr[pixelPtrOffset] = tcuTexture.floatToChannel(stencil, this.m_format.type); 2163 else { 2164 DE_ASSERT(this.m_format.order == tcuTexture.ChannelOrder.DS); 2165 pixelPtr[3 + pixelPtrOffset] = tcuTexture.floatToChannel(stencil, this.m_format.type); 2166 } 2167 } 2168 } 2169 }; 2170 2171 /** 2172 * newFromTextureLevel 2173 * @param {tcuTexture.TextureLevel} level 2174 * @return {tcuTexture.PixelBufferAccess} 2175 */ 2176 tcuTexture.PixelBufferAccess.newFromTextureLevel = function(level) { 2177 var descriptor = new Object(); 2178 descriptor.format = level.getFormat(); 2179 descriptor.width = level.getWidth(); 2180 descriptor.height = level.getHeight(); 2181 descriptor.depth = level.m_depth; 2182 descriptor.data = level.m_data.m_ptr; 2183 2184 return new tcuTexture.PixelBufferAccess(descriptor); 2185 }; 2186 2187 /** 2188 * newFromTextureFormat 2189 * @param {tcuTexture.TextureFormat} format 2190 * @param {number} width 2191 * @param {number} height 2192 * @param {number} depth 2193 * @param {number} rowPitch 2194 * @param {number} slicePitch 2195 * @param {ArrayBuffer} data 2196 */ 2197 tcuTexture.PixelBufferAccess.newFromTextureFormat = function(format, width, height, depth, rowPitch, slicePitch, data) { 2198 var descriptor = new Object(); 2199 descriptor.format = format; 2200 descriptor.width = width; 2201 descriptor.height = height; 2202 descriptor.depth = depth; 2203 descriptor.rowPitch = rowPitch; 2204 descriptor.slicePitch = slicePitch; 2205 descriptor.data = data; 2206 2207 return new tcuTexture.PixelBufferAccess(descriptor); 2208 }; 2209 2210 /* TODO: Port */ 2211 // { 2212 // public: 2213 // tcuTexture.PixelBufferAccess (void) {} 2214 // tcuTexture.PixelBufferAccess (const tcuTexture.TextureFormat& format, int width, int height, int depth, void* data); 2215 2216 // void* getDataPtr (void) const { return m_data; } 2217 2218 // void setPixels (const void* buf, int bufSize) const; 2219 // void setPixel (const tcu::Vec4& color, int x, int y, int z = 0) const; 2220 // void setPixel (const tcu::IVec4& color, int x, int y, int z = 0) const; 2221 // void setPixel (const tcu::UVec4& color, int x, int y, int z = 0) const { setPixel(color.cast<int>(), x, y, z); } 2222 2223 // void setPixDepth (float depth, int x, int y, int z = 0) const; 2224 // void setPixStencil (int stencil, int x, int y, int z = 0) const; 2225 // }; 2226 2227 /** 2228 * @constructor 2229 * @param {tcuTexture.TextureFormat} format 2230 * @param {number} numLevels 2231 */ 2232 tcuTexture.TextureLevelPyramid = function(format, numLevels) { 2233 /* tcuTexture.TextureFormat */this.m_format = format; 2234 /* LevelData */ this.m_data = []; 2235 for (var i = 0; i < numLevels; i++) 2236 this.m_data.push(new tcuTexture.DeqpArrayBuffer()); 2237 /* {Array<tcuTexture.PixelBufferAccess>} */ this.m_access = []; 2238 this.m_access.length = numLevels; 2239 }; 2240 2241 /** @return {boolean} */ 2242 tcuTexture.TextureLevelPyramid.prototype.isLevelEmpty = function(levelNdx) { return this.m_data[levelNdx].empty(); }; 2243 /** @return {tcuTexture.TextureFormat} */ 2244 tcuTexture.TextureLevelPyramid.prototype.getFormat = function() { return this.m_format; }; 2245 /** @return {number} */ 2246 tcuTexture.TextureLevelPyramid.prototype.getNumLevels = function() { return this.m_access.length; }; 2247 /** @return {tcuTexture.PixelBufferAccess} */ 2248 tcuTexture.TextureLevelPyramid.prototype.getLevel = function(ndx) { return this.m_access[ndx]; }; 2249 /** @return {Array<tcuTexture.PixelBufferAccess>} */ 2250 tcuTexture.TextureLevelPyramid.prototype.getLevels = function() { return this.m_access; }; 2251 2252 /** 2253 * @param {number} levelNdx 2254 * @param {number} width 2255 * @param {number} height 2256 * @param {number} depth 2257 */ 2258 tcuTexture.TextureLevelPyramid.prototype.allocLevel = function(levelNdx, width, height, depth) { 2259 var size = this.m_format.getPixelSize() * width * height * depth; 2260 2261 DE_ASSERT(this.isLevelEmpty(levelNdx)); 2262 2263 this.m_data[levelNdx].setStorage(size); 2264 this.m_access[levelNdx] = new tcuTexture.PixelBufferAccess({ 2265 format: this.m_format, 2266 width: width, 2267 height: height, 2268 depth: depth, 2269 data: this.m_data[levelNdx].m_ptr 2270 }); 2271 }; 2272 2273 tcuTexture.TextureLevelPyramid.prototype.clearLevel = function(levelNdx) { 2274 /* TODO: Implement */ 2275 throw new Error('Not implemented'); 2276 }; 2277 2278 /** 2279 * @param {Array<tcuTexture.ConstPixelBufferAccess>} levels 2280 * @param {number} numLevels 2281 * @param {tcuTexture.Sampler} sampler 2282 * @param {number} s 2283 * @param {number} t 2284 * @param {number} depth (integer) 2285 * @param {number=} lod 2286 * @return {Array<number>} Vec4 pixel color 2287 */ 2288 tcuTexture.sampleLevelArray2D = function(levels, numLevels, sampler, s, t, depth, lod) { 2289 // z-offset in 2D textures is layer selector 2290 return tcuTexture.sampleLevelArray2DOffset(levels, numLevels, sampler, [s, t], lod, [0, 0, depth]); 2291 }; 2292 2293 /** 2294 * @param {Array<tcuTexture.ConstPixelBufferAccess>} levels 2295 * @param {number} numLevels 2296 * @param {tcuTexture.Sampler} sampler 2297 * @param {number} s 2298 * @param {number} t 2299 * @param {number} r 2300 * @param {number} lod 2301 * @return {Array<number>} Vec4 pixel color 2302 */ 2303 tcuTexture.sampleLevelArray3D = function(levels, numLevels, sampler, s, t, r, lod) { 2304 return tcuTexture.sampleLevelArray3DOffset(levels, numLevels, sampler, s, t, r, lod, [0, 0, 0]); 2305 }; 2306 2307 /** 2308 * @constructor 2309 * @param {tcuTexture.CubeFace} face 2310 * @param {Array<number>} coords 2311 */ 2312 tcuTexture.CubeFaceCoords = function(face, coords) { 2313 this.face = face; 2314 this.s = coords[0]; 2315 this.t = coords[1]; 2316 }; 2317 2318 /** 2319 * \brief 2D Texture View 2320 * @constructor 2321 * @param {number} numLevels 2322 * @param {?Array<tcuTexture.ConstPixelBufferAccess>} levels 2323 */ 2324 tcuTexture.Texture2DView = function(numLevels, levels) { 2325 this.m_numLevels = numLevels; 2326 this.m_levels = levels; 2327 }; 2328 2329 /** @return {number} */ 2330 tcuTexture.Texture2DView.prototype.getNumLevels = function() { return this.m_numLevels; }; 2331 /** @return {number} */ 2332 tcuTexture.Texture2DView.prototype.getWidth = function() { return this.m_numLevels > 0 ? this.m_levels[0].getWidth() : 0; }; 2333 /** @return {number} */ 2334 tcuTexture.Texture2DView.prototype.getHeight = function() { return this.m_numLevels > 0 ? this.m_levels[0].getHeight() : 0; }; 2335 /** 2336 * @param {number} ndx 2337 * @return {tcuTexture.ConstPixelBufferAccess} 2338 */ 2339 tcuTexture.Texture2DView.prototype.getLevel = function(ndx) { DE_ASSERT(deMath.deInBounds32(ndx, 0, this.m_numLevels)); return this.m_levels[ndx]; }; 2340 /** @return {Array<tcuTexture.ConstPixelBufferAccess>} */ 2341 tcuTexture.Texture2DView.prototype.getLevels = function() { return this.m_levels; }; 2342 2343 /** 2344 * @param {number} baseLevel 2345 * @param {number} maxLevel 2346 * return {tcuTexture.Texture2DView} 2347 */ 2348 tcuTexture.Texture2DView.prototype.getSubView = function(baseLevel, maxLevel) { 2349 var clampedBase = deMath.clamp(baseLevel, 0, this.m_numLevels - 1); 2350 var clampedMax = deMath.clamp(maxLevel, clampedBase, this.m_numLevels - 1); 2351 var numLevels = clampedMax - clampedBase + 1; 2352 return new tcuTexture.Texture2DView(numLevels, this.m_levels.slice(clampedBase, numLevels)); 2353 }; 2354 2355 /** 2356 * @param {tcuTexture.Sampler} sampler 2357 * @param {Array<number>} texCoord 2358 * @param {number=} lod 2359 * @return {Array<number>} Pixel color 2360 */ 2361 tcuTexture.Texture2DView.prototype.sample = function(sampler, texCoord, lod) { 2362 return tcuTexture.sampleLevelArray2D(this.m_levels, this.m_numLevels, sampler, texCoord[0], texCoord[1], 0 /* depth */, lod); 2363 }; 2364 2365 /** 2366 * @param {tcuTexture.Sampler} sampler 2367 * @param {Array<number>} texCoord 2368 * @param {number} lod 2369 * @param {Array<number>} offset 2370 * @return {Array<number>} Pixel color 2371 */ 2372 tcuTexture.Texture2DView.prototype.sampleOffset = function(sampler, texCoord, lod, offset) { 2373 return tcuTexture.sampleLevelArray2DOffset(this.m_levels, this.m_numLevels, sampler, texCoord, lod, [offset[0], offset[1], 0]); 2374 }; 2375 2376 /** 2377 * @param {tcuTexture.Sampler} sampler 2378 * @param {number} ref 2379 * @param {Array<number>} texCoord 2380 * @param {number} lod 2381 * @return {number} 2382 */ 2383 tcuTexture.Texture2DView.prototype.sampleCompare = function(sampler, ref, texCoord, lod) { 2384 return tcuTexture.sampleLevelArray2DCompare(this.m_levels, this.m_numLevels, sampler, ref, texCoord[0], texCoord[1], lod, [0, 0, 0]); 2385 }; 2386 2387 /** 2388 * @param {tcuTexture.Sampler} sampler 2389 * @param {number} ref 2390 * @param {Array<number>} texCoord 2391 * @param {number} lod 2392 * @param {Array<number>} offset 2393 * @return {number} 2394 */ 2395 tcuTexture.Texture2DView.prototype.sampleCompareOffset = function(sampler, ref, texCoord, lod, offset) { 2396 return tcuTexture.sampleLevelArray2DCompare(this.m_levels, this.m_numLevels, sampler, ref, texCoord[0], texCoord[1], lod, [offset[0], offset[1], 0]); 2397 }; 2398 2399 /* TODO: Port 2400 Vec4 sample (const tcuTexture.Sampler& sampler, float s, float t, float lod) const; 2401 Vec4 sampleOffset (const tcuTexture.Sampler& sampler, float s, float t, float lod, const IVec2& offset) const; 2402 float sampleCompare (const tcuTexture.Sampler& sampler, float ref, float s, float t, float lod) const; 2403 float sampleCompareOffset (const tcuTexture.Sampler& sampler, float ref, float s, float t, float lod, const IVec2& offset) const; 2404 2405 Vec4 gatherOffsets (const tcuTexture.Sampler& sampler, float s, float t, int componentNdx, const IVec2 (&offsets)[4]) const; 2406 Vec4 gatherOffsetsCompare(const tcuTexture.Sampler& sampler, float ref, float s, float t, const IVec2 (&offsets)[4]) const; 2407 */ 2408 2409 /** 2410 * @constructor 2411 * @param {number} numLevels 2412 * @param {Array<tcuTexture.ConstPixelBufferAccess>} levels 2413 */ 2414 tcuTexture.Texture2DArrayView = function(numLevels, levels) { 2415 this.m_numLevels = numLevels; 2416 this.m_levels = levels; 2417 }; 2418 2419 /** @return {number} */ 2420 tcuTexture.Texture2DArrayView.prototype.getNumLevels = function() { return this.m_numLevels; }; 2421 /** @return {number} */ 2422 tcuTexture.Texture2DArrayView.prototype.getWidth = function() { return this.m_numLevels > 0 ? this.m_levels[0].getWidth() : 0; }; 2423 /** @return {number} */ 2424 tcuTexture.Texture2DArrayView.prototype.getHeight = function() { return this.m_numLevels > 0 ? this.m_levels[0].getHeight() : 0; }; 2425 /** @return {number} */ 2426 tcuTexture.Texture2DArrayView.prototype.getNumLayers = function() { return this.m_numLevels > 0 ? this.m_levels[0].getDepth() : 0; }; 2427 /** 2428 * @param {number} ndx 2429 * @return {tcuTexture.ConstPixelBufferAccess} 2430 */ 2431 tcuTexture.Texture2DArrayView.prototype.getLevel = function(ndx) { DE_ASSERT(deMath.deInBounds32(ndx, 0, this.m_numLevels)); return this.m_levels[ndx]; }; 2432 /** @return {Array<tcuTexture.ConstPixelBufferAccess>} */ 2433 tcuTexture.Texture2DArrayView.prototype.getLevels = function() { return this.m_levels; }; 2434 2435 /** 2436 * @param {number} r 2437 * @return {number} layer corresponding to requested sampling 'r' coordinate 2438 */ 2439 tcuTexture.Texture2DArrayView.prototype.selectLayer = function(r) { 2440 DE_ASSERT(this.m_numLevels > 0 && this.m_levels); 2441 return deMath.clamp(Math.round(r), 0, this.m_levels[0].getDepth() - 1); 2442 }; 2443 2444 /** 2445 * @param {tcuTexture.Sampler} sampler 2446 * @param {Array<number>} texCoord 2447 * @param {number=} lod 2448 * @return {Array<number>} Pixel color 2449 */ 2450 tcuTexture.Texture2DArrayView.prototype.sample = function(sampler, texCoord, lod) { 2451 lod = lod || 0; 2452 return tcuTexture.sampleLevelArray2D(this.m_levels, this.m_numLevels, sampler, texCoord[0], texCoord[1], this.selectLayer(texCoord[2]), lod); 2453 }; 2454 2455 /** 2456 * @param {tcuTexture.Sampler} sampler 2457 * @param {Array<number>} texCoord 2458 * @param {number} lod 2459 * @param {Array<number>} offset 2460 * @return {Array<number>} 2461 */ 2462 tcuTexture.Texture2DArrayView.prototype.sampleOffset = function(sampler, texCoord, lod, offset) { 2463 return tcuTexture.sampleLevelArray2DOffset(this.m_levels, this.m_numLevels, sampler, texCoord, lod, [offset[0], offset[1], this.selectLayer(texCoord[2])]); 2464 }; 2465 2466 /** 2467 * @param {tcuTexture.Sampler} sampler 2468 * @param {number} ref 2469 * @param {Array<number>} texCoord 2470 * @param {number} lod 2471 * @param {Array<number>} offset 2472 * @return {number} 2473 */ 2474 tcuTexture.Texture2DArrayView.prototype.sampleCompareOffset = function(sampler, ref, texCoord, lod, offset) { 2475 return tcuTexture.sampleLevelArray2DCompare(this.m_levels, this.m_numLevels, sampler, ref, texCoord[0], texCoord[1], lod, [offset[0], offset[1], this.selectLayer(texCoord[2])]); 2476 }; 2477 2478 /** 2479 * @param {tcuTexture.Sampler} sampler 2480 * @param {number} ref 2481 * @param {Array<number>} texCoord 2482 * @param {number} lod 2483 * @return {number} 2484 */ 2485 tcuTexture.Texture2DArrayView.prototype.sampleCompare = function(sampler, ref, texCoord, lod) { 2486 return tcuTexture.sampleLevelArray2DCompare(this.m_levels, this.m_numLevels, sampler, ref, texCoord[0], texCoord[1], lod, [0, 0, this.selectLayer(texCoord[2])]); 2487 }; 2488 2489 /** 2490 * @param {Array<tcuTexture.ConstPixelBufferAccess>} levels 2491 * @param {number} numLevels 2492 * @param {tcuTexture.Sampler} sampler 2493 * @param {Array<number>} texCoord 2494 * @param {number} lod 2495 * @param {Array<number>} offset 2496 * @return {Array<number>} 2497 */ 2498 tcuTexture.sampleLevelArray2DOffset = function(levels, numLevels, sampler, texCoord, lod, offset) { 2499 /** @type {boolean} */ var magnified = lod <= sampler.lodThreshold; 2500 /** @type {tcuTexture.FilterMode} */ var filterMode = magnified ? sampler.magFilter : sampler.minFilter; 2501 /** @type {number} */ var maxLevel; 2502 /** @type {tcuTexture.FilterMode} */ var levelFilter; 2503 switch (filterMode) { 2504 case tcuTexture.FilterMode.NEAREST: return levels[0].sample2DOffset(sampler, filterMode, texCoord[0], texCoord[1], offset); 2505 case tcuTexture.FilterMode.LINEAR: return levels[0].sample2DOffset(sampler, filterMode, texCoord[0], texCoord[1], offset); 2506 2507 case tcuTexture.FilterMode.NEAREST_MIPMAP_NEAREST: 2508 case tcuTexture.FilterMode.LINEAR_MIPMAP_NEAREST: 2509 maxLevel = numLevels - 1; 2510 /** @type {number} */ var level = deMath.clamp(Math.ceil(lod + 0.5) - 1, 0, maxLevel); 2511 levelFilter = (filterMode === tcuTexture.FilterMode.LINEAR_MIPMAP_NEAREST) ? tcuTexture.FilterMode.LINEAR : tcuTexture.FilterMode.NEAREST; 2512 2513 return levels[level].sample2DOffset(sampler, levelFilter, texCoord[0], texCoord[1], offset); 2514 2515 case tcuTexture.FilterMode.NEAREST_MIPMAP_LINEAR: 2516 case tcuTexture.FilterMode.LINEAR_MIPMAP_LINEAR: 2517 maxLevel = numLevels - 1; 2518 /** @type {number} */ var level0 = deMath.clamp(Math.floor(lod), 0, maxLevel); 2519 /** @type {number} */ var level1 = Math.min(maxLevel, level0 + 1); 2520 levelFilter = (filterMode === tcuTexture.FilterMode.LINEAR_MIPMAP_LINEAR) ? tcuTexture.FilterMode.LINEAR : tcuTexture.FilterMode.NEAREST; 2521 /** @type {number} */ var f = deMath.deFloatFrac(lod); 2522 /** @type {Array<number>} */ var t0 = levels[level0].sample2DOffset(sampler, levelFilter, texCoord[0], texCoord[1], offset); 2523 /** @type {Array<number>} */ var t1 = levels[level1].sample2DOffset(sampler, levelFilter, texCoord[0], texCoord[1], offset); 2524 2525 return deMath.add(deMath.scale(t0, (1.0 - f)), deMath.scale(t1, f)); 2526 2527 default: 2528 return [0.0, 0.0, 0.0, 0.0]; 2529 } 2530 }; 2531 2532 /** 2533 * @constructor 2534 * @param {number} numLevels 2535 * @param {Array<tcuTexture.ConstPixelBufferAccess>} levels 2536 */ 2537 tcuTexture.Texture3DView = function(numLevels, levels) { 2538 this.m_numLevels = numLevels; 2539 this.m_levels = levels; 2540 }; 2541 2542 /** @return {number} */ 2543 tcuTexture.Texture3DView.prototype.getNumLevels = function() { return this.m_numLevels; }; 2544 /** @return {number} */ 2545 tcuTexture.Texture3DView.prototype.getWidth = function() { return this.m_numLevels > 0 ? this.m_levels[0].getWidth() : 0; }; 2546 /** @return {number} */ 2547 tcuTexture.Texture3DView.prototype.getHeight = function() { return this.m_numLevels > 0 ? this.m_levels[0].getHeight() : 0; }; 2548 /** @return {number} */ 2549 tcuTexture.Texture3DView.prototype.getDepth = function() { return this.m_numLevels > 0 ? this.m_levels[0].getDepth() : 0; }; 2550 /** 2551 * @param {number} ndx 2552 * @return {tcuTexture.ConstPixelBufferAccess} 2553 */ 2554 tcuTexture.Texture3DView.prototype.getLevel = function(ndx) { DE_ASSERT(deMath.deInBounds32(ndx, 0, this.m_numLevels)); return this.m_levels[ndx]; }; 2555 /** @return {Array<tcuTexture.ConstPixelBufferAccess>} */ 2556 tcuTexture.Texture3DView.prototype.getLevels = function() { return this.m_levels; }; 2557 2558 /** 2559 * @param {number} baseLevel 2560 * @param {number} maxLevel 2561 * return {tcuTexture.Texture3DView} 2562 */ 2563 tcuTexture.Texture3DView.prototype.getSubView = function(baseLevel, maxLevel) { 2564 var clampedBase = deMath.clamp(baseLevel, 0, this.m_numLevels - 1); 2565 var clampedMax = deMath.clamp(maxLevel, clampedBase, this.m_numLevels - 1); 2566 var numLevels = clampedMax - clampedBase + 1; 2567 return new tcuTexture.Texture3DView(numLevels, this.m_levels.slice(clampedBase, numLevels)); 2568 }; 2569 2570 /** 2571 * @param {tcuTexture.Sampler} sampler 2572 * @param {Array<number>} texCoord 2573 * @param {number=} lod 2574 * @return {Array<number>} Pixel color 2575 */ 2576 tcuTexture.Texture3DView.prototype.sample = function(sampler, texCoord, lod) { 2577 lod = lod || 0; 2578 return tcuTexture.sampleLevelArray3D(this.m_levels, this.m_numLevels, sampler, texCoord[0], texCoord[1], texCoord[2], lod); 2579 }; 2580 2581 /** 2582 * @param {tcuTexture.Sampler} sampler 2583 * @param {number} ref 2584 * @param {Array<number>} texCoord 2585 * @param {number} lod 2586 * @return {number} 2587 */ 2588 tcuTexture.Texture3DView.prototype.sampleCompare = function(sampler, ref, texCoord, lod) { 2589 throw new Error('Unimplemented'); 2590 }; 2591 2592 /** 2593 * @param {tcuTexture.Sampler} sampler 2594 * @param {Array<number>} texCoord 2595 * @param {number} lod 2596 * @param {Array<number>} offset 2597 * @return {Array<number>} 2598 */ 2599 tcuTexture.Texture3DView.prototype.sampleOffset = function(sampler, texCoord, lod, offset) { 2600 return tcuTexture.sampleLevelArray3DOffset(this.m_levels, this.m_numLevels, sampler, texCoord[0], texCoord[1], texCoord[2], lod, offset); 2601 }; 2602 2603 /* TODO: All view classes are very similar. They should have a common base class */ 2604 2605 /** 2606 * @param {Array<tcuTexture.ConstPixelBufferAccess>} levels 2607 * @param {number} numLevels 2608 * @param {tcuTexture.Sampler} sampler 2609 * @param {number} s 2610 * @param {number} t 2611 * @param {number} r 2612 * @param {number} lod 2613 * @param {Array<number>} offset 2614 * @return {Array<number>} 2615 */ 2616 tcuTexture.sampleLevelArray3DOffset = function(levels, numLevels, sampler, s, t, r, lod, offset) { 2617 /** @type {boolean} */ var magnified = lod <= sampler.lodThreshold; 2618 /** @type {tcuTexture.FilterMode} */ var filterMode = magnified ? sampler.magFilter : sampler.minFilter; 2619 /** @type {number} */ var maxLevel; 2620 /** @type {tcuTexture.FilterMode} */ var levelFilter; 2621 switch (filterMode) { 2622 case tcuTexture.FilterMode.NEAREST: return levels[0].sample3DOffset(sampler, filterMode, s, t, r, offset); 2623 case tcuTexture.FilterMode.LINEAR: return levels[0].sample3DOffset(sampler, filterMode, s, t, r, offset); 2624 2625 case tcuTexture.FilterMode.NEAREST_MIPMAP_NEAREST: 2626 case tcuTexture.FilterMode.LINEAR_MIPMAP_NEAREST: 2627 maxLevel = numLevels - 1; 2628 /** @type {number} */ var level = deMath.clamp(Math.ceil(lod + 0.5) - 1, 0, maxLevel); 2629 levelFilter = (filterMode === tcuTexture.FilterMode.LINEAR_MIPMAP_NEAREST) ? tcuTexture.FilterMode.LINEAR : tcuTexture.FilterMode.NEAREST; 2630 2631 return levels[level].sample3DOffset(sampler, levelFilter, s, t, r, offset); 2632 2633 case tcuTexture.FilterMode.NEAREST_MIPMAP_LINEAR: 2634 case tcuTexture.FilterMode.LINEAR_MIPMAP_LINEAR: 2635 maxLevel = numLevels - 1; 2636 /** @type {number} */ var level0 = deMath.clamp(Math.floor(lod), 0, maxLevel); 2637 /** @type {number} */ var level1 = Math.min(maxLevel, level0 + 1); 2638 levelFilter = (filterMode === tcuTexture.FilterMode.LINEAR_MIPMAP_LINEAR) ? tcuTexture.FilterMode.LINEAR : tcuTexture.FilterMode.NEAREST; 2639 /** @type {number} */ var f = deMath.deFloatFrac(lod); 2640 /** @type {Array<number>} */ var t0 = levels[level0].sample3DOffset(sampler, levelFilter, s, t, r, offset); 2641 /** @type {Array<number>} */ var t1 = levels[level1].sample3DOffset(sampler, levelFilter, s, t, r, offset); 2642 2643 return deMath.add(deMath.scale(t0, (1.0 - f)), deMath.scale(t1, f)); 2644 2645 default: 2646 throw new Error('Filter mode not supported'); 2647 } 2648 }; 2649 2650 /** 2651 * @param {number} width 2652 * @param {number=} height 2653 * @param {number=} depth 2654 * @return {number} Number of pyramid levels 2655 */ 2656 tcuTexture.computeMipPyramidLevels = function(width, height, depth) { 2657 if (depth !== undefined) 2658 return Math.floor(Math.log2(Math.max(width, Math.max(height, depth)))) + 1; 2659 else if (height !== undefined) 2660 return Math.floor(Math.log2(Math.max(width, height))) + 1; 2661 else 2662 return Math.floor(Math.log2(width)) + 1; 2663 }; 2664 2665 /** 2666 * @param {number} baseLevelSize 2667 * @param {number} levelNdx 2668 */ 2669 tcuTexture.getMipPyramidLevelSize = function(baseLevelSize, levelNdx) { 2670 return Math.max(baseLevelSize >> levelNdx, 1); 2671 }; 2672 2673 /** 2674 * @param {Array<tcuTexture.ConstPixelBufferAccess>} faceAccesses 2675 * @param {tcuTexture.CubeFace} baseFace 2676 * @param {number} u 2677 * @param {number} v 2678 * @param {number} depth 2679 * @return {Array<Array<number>>} 2680 */ 2681 tcuTexture.getCubeLinearSamples = function(faceAccesses, baseFace, u, v, depth) { 2682 DE_ASSERT(faceAccesses[0].getWidth() == faceAccesses[0].getHeight()); 2683 /** @type {Array<Array<number>>} */ var dst = []; 2684 var size = faceAccesses[0].getWidth(); 2685 var x0 = Math.floor(u - 0.5); 2686 var x1 = x0 + 1; 2687 var y0 = Math.floor(v - 0.5); 2688 var y1 = y0 + 1; 2689 var baseSampleCoords = 2690 [ 2691 [x0, y0], 2692 [x1, y0], 2693 [x0, y1], 2694 [x1, y1] 2695 ]; 2696 /** @type {Array<Array<number>>} */ var sampleColors = []; 2697 /** @type {Array<boolean>} */ var hasBothCoordsOutOfBounds = []; //!< Whether correctCubeFace() returns CUBEFACE_LAST, i.e. both u and v are out of bounds. 2698 2699 // Find correct faces and coordinates for out-of-bounds sample coordinates. 2700 2701 for (var i = 0; i < 4; i++) { 2702 /** @type {tcuTexture.CubeFaceCoords} */ var coords = tcuTexture.remapCubeEdgeCoords(new tcuTexture.CubeFaceCoords(baseFace, baseSampleCoords[i]), size); 2703 hasBothCoordsOutOfBounds[i] = coords == null; 2704 if (!hasBothCoordsOutOfBounds[i]) 2705 sampleColors[i] = tcuTexture.lookup(faceAccesses[coords.face], coords.s, coords.t, depth); 2706 } 2707 2708 // If a sample was out of bounds in both u and v, we get its color from the average of the three other samples. 2709 // \note This averaging behavior is not required by the GLES3 spec (though it is recommended). GLES3 spec only 2710 // requires that if the three other samples all have the same color, then the doubly-out-of-bounds sample 2711 // must have this color as well. 2712 2713 var bothOutOfBoundsNdx = -1; 2714 for (var i = 0; i < 4; i++) { 2715 if (hasBothCoordsOutOfBounds[i]) { 2716 DE_ASSERT(bothOutOfBoundsNdx < 0); // Only one sample can be out of bounds in both u and v. 2717 bothOutOfBoundsNdx = i; 2718 } 2719 } 2720 if (bothOutOfBoundsNdx != -1) { 2721 sampleColors[bothOutOfBoundsNdx] = [0, 0, 0, 0]; 2722 for (var i = 0; i < 4; i++) 2723 if (i != bothOutOfBoundsNdx) 2724 sampleColors[bothOutOfBoundsNdx] = deMath.add(sampleColors[bothOutOfBoundsNdx], sampleColors[i]); 2725 2726 sampleColors[bothOutOfBoundsNdx] = deMath.scale(sampleColors[bothOutOfBoundsNdx], (1.0 / 3.0)); 2727 } 2728 2729 for (var i = 0; i < sampleColors.length; i++) 2730 dst[i] = sampleColors[i]; 2731 2732 return dst; 2733 }; 2734 2735 // \todo [2014-02-19 pyry] Optimize faceAccesses 2736 /** 2737 * @param {Array<tcuTexture.ConstPixelBufferAccess>} faceAccesses 2738 * @param {tcuTexture.CubeFace} baseFace 2739 * @param {tcuTexture.Sampler} sampler 2740 * @param {number} s 2741 * @param {number} t 2742 * @param {number} depth 2743 * @return {Array<number>} 2744 */ 2745 tcuTexture.sampleCubeSeamlessLinear = function(faceAccesses, baseFace, sampler, s, t, depth) { 2746 DE_ASSERT(faceAccesses[0].getWidth() == faceAccesses[0].getHeight()); 2747 2748 var size = faceAccesses[0].getWidth(); 2749 // Non-normalized coordinates. 2750 var u = s; 2751 var v = t; 2752 2753 if (sampler.normalizedCoords) { 2754 u = tcuTexture.unnormalize(sampler.wrapS, s, size); 2755 v = tcuTexture.unnormalize(sampler.wrapT, t, size); 2756 } 2757 2758 // Get sample colors. 2759 2760 /** @type {Array<Array<number>>} */ var sampleColors = tcuTexture.getCubeLinearSamples(faceAccesses, baseFace, u, v, depth); 2761 2762 // Interpolate. 2763 2764 var a = deMath.deFloatFrac(u - 0.5); 2765 var b = deMath.deFloatFrac(v - 0.5); 2766 2767 return deMath.add((deMath.scale(deMath.scale(sampleColors[0], (1.0 - a)), (1.0 - b))), 2768 deMath.add((deMath.scale(deMath.scale(sampleColors[1], (a)), (1.0 - b))), 2769 deMath.add((deMath.scale(deMath.scale(sampleColors[2], (1.0 - a)), (b))), 2770 (deMath.scale(deMath.scale(sampleColors[3], (a)), (b)))))); 2771 }; 2772 2773 /** 2774 * @param {Array<Array<tcuTexture.ConstPixelBufferAccess>>} faces 2775 * @param {number} numLevels 2776 * @param {tcuTexture.CubeFace} face 2777 * @param {tcuTexture.Sampler} sampler 2778 * @param {number} s 2779 * @param {number} t 2780 * @param {number} depth 2781 * @param {number=} lod 2782 * @return {Array<number>} 2783 */ 2784 tcuTexture.sampleLevelArrayCubeSeamless = function(faces, numLevels, face, sampler, s, t, depth, lod) { 2785 lod = lod || 0; 2786 var magnified = lod <= sampler.lodThreshold; 2787 /** @type {tcuTexture.FilterMode} */ var filterMode = magnified ? sampler.magFilter : sampler.minFilter; 2788 /** @type {Array<tcuTexture.ConstPixelBufferAccess>} */ var faceAccesses = []; 2789 /** @type {tcuTexture.FilterMode}*/ var levelFilter; 2790 2791 switch (filterMode) { 2792 case tcuTexture.FilterMode.NEAREST: 2793 return tcuTexture.sampleCubeSeamlessNearest(faces[face][0], sampler, s, t, depth); 2794 2795 case tcuTexture.FilterMode.LINEAR: { 2796 faceAccesses = []; 2797 for (var i = 0; i < Object.keys(tcuTexture.CubeFace).length; i++) 2798 faceAccesses[i] = faces[i][0]; 2799 2800 return tcuTexture.sampleCubeSeamlessLinear(faceAccesses, face, sampler, s, t, depth); 2801 } 2802 2803 case tcuTexture.FilterMode.NEAREST_MIPMAP_NEAREST: 2804 case tcuTexture.FilterMode.LINEAR_MIPMAP_NEAREST: { 2805 var maxLevel = numLevels - 1; 2806 var level = deMath.clamp(Math.ceil(lod + 0.5) - 1, 0, maxLevel); 2807 levelFilter = (filterMode == tcuTexture.FilterMode.LINEAR_MIPMAP_NEAREST) ? tcuTexture.FilterMode.LINEAR : tcuTexture.FilterMode.NEAREST; 2808 2809 if (levelFilter == tcuTexture.FilterMode.NEAREST) 2810 return tcuTexture.sampleCubeSeamlessNearest(faces[face][level], sampler, s, t, depth); 2811 else { 2812 DE_ASSERT(levelFilter == tcuTexture.FilterMode.LINEAR); 2813 2814 faceAccesses = []; 2815 for (var i = 0; i < Object.keys(tcuTexture.CubeFace).length; i++) 2816 faceAccesses[i] = faces[i][level]; 2817 2818 return tcuTexture.sampleCubeSeamlessLinear(faceAccesses, face, sampler, s, t, depth); 2819 } 2820 } 2821 2822 case tcuTexture.FilterMode.NEAREST_MIPMAP_LINEAR: 2823 case tcuTexture.FilterMode.LINEAR_MIPMAP_LINEAR: { 2824 var maxLevel = numLevels - 1; 2825 var level0 = deMath.clamp(Math.floor(lod), 0, maxLevel); 2826 var level1 = Math.min(maxLevel, level0 + 1); 2827 levelFilter = (filterMode == tcuTexture.FilterMode.LINEAR_MIPMAP_LINEAR) ? tcuTexture.FilterMode.LINEAR : tcuTexture.FilterMode.NEAREST; 2828 var f = deMath.deFloatFrac(lod); 2829 var t0 = []; 2830 var t1 = []; 2831 2832 if (levelFilter == tcuTexture.FilterMode.NEAREST) { 2833 t0 = tcuTexture.sampleCubeSeamlessNearest(faces[face][level0], sampler, s, t, depth); 2834 t1 = tcuTexture.sampleCubeSeamlessNearest(faces[face][level1], sampler, s, t, depth); 2835 } else { 2836 DE_ASSERT(levelFilter == tcuTexture.FilterMode.LINEAR); 2837 2838 /** @type {Array<tcuTexture.ConstPixelBufferAccess>}*/ var faceAccesses0 = []; 2839 /** @type {Array<tcuTexture.ConstPixelBufferAccess>}*/ var faceAccesses1 = []; 2840 for (var i = 0; i < Object.keys(tcuTexture.CubeFace).length; i++) { 2841 faceAccesses0[i] = faces[i][level0]; 2842 faceAccesses1[i] = faces[i][level1]; 2843 } 2844 2845 t0 = tcuTexture.sampleCubeSeamlessLinear(faceAccesses0, face, sampler, s, t, depth); 2846 t1 = tcuTexture.sampleCubeSeamlessLinear(faceAccesses1, face, sampler, s, t, depth); 2847 } 2848 2849 return deMath.add(deMath.scale(t0, (1.0 - f)), deMath.scale(t1, f)); 2850 } 2851 2852 default: 2853 throw new Error('Unsupported filter mode'); 2854 } 2855 }; 2856 2857 /** 2858 * @param {tcuTexture.ConstPixelBufferAccess} faceAccess 2859 * @param {tcuTexture.Sampler} sampler 2860 * @param {number} ref 2861 * @param {number} s 2862 * @param {number} t 2863 * @param {number=} depth 2864 * @return {number} 2865 */ 2866 tcuTexture.sampleCubeSeamlessNearestCompare = function(faceAccess, sampler, ref, s, t, depth) { 2867 depth = depth ? depth : 0; 2868 /** @type {tcuTexture.Sampler} */ var clampingSampler = deUtil.clone(sampler); 2869 clampingSampler.wrapS = tcuTexture.WrapMode.CLAMP_TO_EDGE; 2870 clampingSampler.wrapT = tcuTexture.WrapMode.CLAMP_TO_EDGE; 2871 return faceAccess.sample2DCompare(clampingSampler, tcuTexture.FilterMode.NEAREST, ref, s, t, [0, 0, depth]); 2872 }; 2873 2874 /** 2875 * @param {Array<tcuTexture.ConstPixelBufferAccess>} faceAccesses 2876 * @param {tcuTexture.CubeFace} baseFace 2877 * @param {tcuTexture.Sampler} sampler 2878 * @param {number} ref 2879 * @param {number} s 2880 * @param {number} t 2881 * @return {number} 2882 */ 2883 tcuTexture.sampleCubeSeamlessLinearCompare = function(faceAccesses, baseFace, sampler, ref, s, t) { 2884 DE_ASSERT(faceAccesses[0].getWidth() == faceAccesses[0].getHeight()); 2885 2886 var size = faceAccesses[0].getWidth(); 2887 // Non-normalized coordinates. 2888 var u = s; 2889 var v = t; 2890 2891 if (sampler.normalizedCoords) { 2892 u = tcuTexture.unnormalize(sampler.wrapS, s, size); 2893 v = tcuTexture.unnormalize(sampler.wrapT, t, size); 2894 } 2895 2896 var x0 = Math.floor(u - 0.5); 2897 var x1 = x0 + 1; 2898 var y0 = Math.floor(v - 0.5); 2899 var y1 = y0 + 1; 2900 var baseSampleCoords = [ 2901 [x0, y0], 2902 [x1, y0], 2903 [x0, y1], 2904 [x1, y1] 2905 ]; 2906 var sampleRes = []; 2907 var hasBothCoordsOutOfBounds = []; //!< Whether correctCubeFace() returns CUBEFACE_LAST, i.e. both u and v are out of bounds. 2908 2909 // Find correct faces and coordinates for out-of-bounds sample coordinates. 2910 2911 for (var i = 0; i < 4; i++) { 2912 /** @type {tcuTexture.CubeFaceCoords} */ var coords = tcuTexture.remapCubeEdgeCoords(new tcuTexture.CubeFaceCoords(baseFace, baseSampleCoords[i]), size); 2913 hasBothCoordsOutOfBounds[i] = coords == null; 2914 2915 if (!hasBothCoordsOutOfBounds[i]) { 2916 var isFixedPointDepth = tcuTexture.isFixedPointDepthTextureFormat(faceAccesses[coords.face].getFormat()); 2917 2918 sampleRes[i] = tcuTexture.execCompare(faceAccesses[coords.face].getPixel(coords.s, coords.t), sampler.compare, sampler.compareChannel, ref, isFixedPointDepth); 2919 } 2920 } 2921 2922 // If a sample was out of bounds in both u and v, we get its color from the average of the three other samples. 2923 // \note This averaging behavior is not required by the GLES3 spec (though it is recommended). GLES3 spec only 2924 // requires that if the three other samples all have the same color, then the doubly-out-of-bounds sample 2925 // must have this color as well. 2926 2927 var bothOutOfBoundsNdx = -1; 2928 for (var i = 0; i < 4; i++) { 2929 if (hasBothCoordsOutOfBounds[i]) { 2930 DE_ASSERT(bothOutOfBoundsNdx < 0); // Only one sample can be out of bounds in both u and v. 2931 bothOutOfBoundsNdx = i; 2932 } 2933 } 2934 if (bothOutOfBoundsNdx != -1) { 2935 sampleRes[bothOutOfBoundsNdx] = 0.0; 2936 for (var i = 0; i < 4; i++) 2937 if (i != bothOutOfBoundsNdx) 2938 sampleRes[bothOutOfBoundsNdx] += sampleRes[i]; 2939 2940 sampleRes[bothOutOfBoundsNdx] = sampleRes[bothOutOfBoundsNdx] * (1.0 / 3.0); 2941 } 2942 2943 // Interpolate. 2944 2945 var a = deMath.deFloatFrac(u - 0.5); 2946 var b = deMath.deFloatFrac(v - 0.5); 2947 2948 return (sampleRes[0] * (1.0 - a) * (1.0 - b)) + 2949 (sampleRes[1] * (a) * (1.0 - b)) + 2950 (sampleRes[2] * (1.0 - a) * (b)) + 2951 (sampleRes[3] * (a) * (b)); 2952 }; 2953 2954 /** 2955 * @param {tcuTexture.ConstPixelBufferAccess} faceAccess 2956 * @param {tcuTexture.Sampler} sampler 2957 * @param {number} s 2958 * @param {number} t 2959 * @param {number} depth 2960 * @return {Array<number>} 2961 */ 2962 tcuTexture.sampleCubeSeamlessNearest = function(faceAccess, sampler, s, t, depth) { 2963 /** @type {tcuTexture.Sampler} */ var clampingSampler = sampler; 2964 clampingSampler.wrapS = tcuTexture.WrapMode.CLAMP_TO_EDGE; 2965 clampingSampler.wrapT = tcuTexture.WrapMode.CLAMP_TO_EDGE; 2966 return faceAccess.sample2D(clampingSampler, tcuTexture.FilterMode.NEAREST, s, t, depth); 2967 }; 2968 2969 /** 2970 * @param {Array<number>} coords Vec3 cube coordinates 2971 * @return {tcuTexture.CubeFaceCoords} 2972 */ 2973 tcuTexture.getCubeFaceCoords = function(coords) { 2974 var face = tcuTexture.selectCubeFace(coords); 2975 return new tcuTexture.CubeFaceCoords(face, tcuTexture.projectToFace(face, coords)); 2976 }; 2977 2978 /** 2979 * @param {Array<Array<tcuTexture.ConstPixelBufferAccess>>} faces 2980 * @param {number} numLevels 2981 * @param {tcuTexture.CubeFace} face 2982 * @param {tcuTexture.Sampler} sampler 2983 * @param {number} ref 2984 * @param {number} s 2985 * @param {number} t 2986 * @param {number} lod 2987 * @return {number} 2988 */ 2989 tcuTexture.sampleLevelArrayCubeSeamlessCompare = function(faces, numLevels, face, sampler, ref, s, t, lod) { 2990 var magnified = lod <= sampler.lodThreshold; 2991 /** @type {tcuTexture.FilterMode}*/ var filterMode = magnified ? sampler.magFilter : sampler.minFilter; 2992 /** @type {Array<tcuTexture.ConstPixelBufferAccess>} */ var faceAccesses = []; 2993 /** @type {tcuTexture.FilterMode} */ var levelFilter; 2994 2995 switch (filterMode) { 2996 case tcuTexture.FilterMode.NEAREST: 2997 return tcuTexture.sampleCubeSeamlessNearestCompare(faces[face][0], sampler, ref, s, t); 2998 2999 case tcuTexture.FilterMode.LINEAR: { 3000 faceAccesses = []; 3001 for (var i = 0; i < Object.keys(tcuTexture.CubeFace).length; i++) 3002 faceAccesses[i] = faces[i][0]; 3003 3004 return tcuTexture.sampleCubeSeamlessLinearCompare(faceAccesses, face, sampler, ref, s, t); 3005 } 3006 3007 case tcuTexture.FilterMode.NEAREST_MIPMAP_NEAREST: 3008 case tcuTexture.FilterMode.LINEAR_MIPMAP_NEAREST: { 3009 var maxLevel = numLevels - 1; 3010 var level = deMath.clamp(Math.ceil(lod + 0.5) - 1, 0, maxLevel); 3011 levelFilter = filterMode == tcuTexture.FilterMode.LINEAR_MIPMAP_NEAREST ? tcuTexture.FilterMode.LINEAR : tcuTexture.FilterMode.NEAREST; 3012 3013 if (levelFilter == tcuTexture.FilterMode.NEAREST) 3014 return tcuTexture.sampleCubeSeamlessNearestCompare(faces[face][level], sampler, ref, s, t); 3015 else { 3016 DE_ASSERT(levelFilter == tcuTexture.FilterMode.LINEAR); 3017 3018 faceAccesses = []; 3019 for (var i = 0; i < Object.keys(tcuTexture.CubeFace).length; i++) 3020 faceAccesses[i] = faces[i][level]; 3021 3022 return tcuTexture.sampleCubeSeamlessLinearCompare(faceAccesses, face, sampler, ref, s, t); 3023 } 3024 } 3025 3026 case tcuTexture.FilterMode.NEAREST_MIPMAP_LINEAR: 3027 case tcuTexture.FilterMode.LINEAR_MIPMAP_LINEAR: { 3028 var maxLevel = numLevels - 1; 3029 var level0 = deMath.clamp(Math.floor(lod), 0, maxLevel); 3030 var level1 = Math.min(maxLevel, level0 + 1); 3031 levelFilter = (filterMode == tcuTexture.FilterMode.LINEAR_MIPMAP_LINEAR) ? tcuTexture.FilterMode.LINEAR : tcuTexture.FilterMode.NEAREST; 3032 var f = deMath.deFloatFrac(lod); 3033 var t0; 3034 var t1; 3035 3036 if (levelFilter == tcuTexture.FilterMode.NEAREST) { 3037 t0 = tcuTexture.sampleCubeSeamlessNearestCompare(faces[face][level0], sampler, ref, s, t); 3038 t1 = tcuTexture.sampleCubeSeamlessNearestCompare(faces[face][level1], sampler, ref, s, t); 3039 } else { 3040 DE_ASSERT(levelFilter == tcuTexture.FilterMode.LINEAR); 3041 3042 /** @type {Array<tcuTexture.ConstPixelBufferAccess>} */ var faceAccesses0 = []; 3043 /** @type {Array<tcuTexture.ConstPixelBufferAccess>} */ var faceAccesses1 = []; 3044 for (var i = 0; i < Object.keys(tcuTexture.CubeFace).length; i++) { 3045 faceAccesses0[i] = faces[i][level0]; 3046 faceAccesses1[i] = faces[i][level1]; 3047 } 3048 3049 t0 = tcuTexture.sampleCubeSeamlessLinearCompare(faceAccesses0, face, sampler, ref, s, t); 3050 t1 = tcuTexture.sampleCubeSeamlessLinearCompare(faceAccesses1, face, sampler, ref, s, t); 3051 } 3052 3053 return t0 * (1.0 - f) + t1 * f; 3054 } 3055 3056 default: 3057 throw new Error('Unsupported filter mode'); 3058 } 3059 }; 3060 3061 /** 3062 * @constructor 3063 * @extends {tcuTexture.TextureLevelPyramid} 3064 * @param {tcuTexture.TextureFormat} format 3065 * @param {number} width 3066 * @param {number} height 3067 */ 3068 tcuTexture.Texture2D = function(format, width, height) { 3069 tcuTexture.TextureLevelPyramid.call(this, format, tcuTexture.computeMipPyramidLevels(width, height)); 3070 this.m_width = width; 3071 this.m_height = height; 3072 this.m_view = new tcuTexture.Texture2DView(this.getNumLevels(), this.getLevels()); 3073 }; 3074 3075 tcuTexture.Texture2D.prototype = Object.create(tcuTexture.TextureLevelPyramid.prototype); 3076 tcuTexture.Texture2D.prototype.constructor = tcuTexture.Texture2D; 3077 3078 tcuTexture.Texture2D.prototype.getWidth = function() { return this.m_width; }; 3079 tcuTexture.Texture2D.prototype.getHeight = function() { return this.m_height; }; 3080 /** @return {tcuTexture.Texture2DView} */ 3081 tcuTexture.Texture2D.prototype.getView = function() { return this.m_view; }; 3082 3083 /** 3084 * @param {number} baseLevel 3085 * @param {number} maxLevel 3086 * @return {tcuTexture.Texture2DView} 3087 */ 3088 tcuTexture.Texture2D.prototype.getSubView = function(baseLevel, maxLevel) { return this.m_view.getSubView(baseLevel, maxLevel); }; 3089 3090 /** 3091 * @param {number} levelNdx 3092 */ 3093 tcuTexture.Texture2D.prototype.allocLevel = function(levelNdx) { 3094 DE_ASSERT(deMath.deInBounds32(levelNdx, 0, this.getNumLevels())); 3095 3096 var width = tcuTexture.getMipPyramidLevelSize(this.m_width, levelNdx); 3097 var height = tcuTexture.getMipPyramidLevelSize(this.m_height, levelNdx); 3098 3099 tcuTexture.TextureLevelPyramid.prototype.allocLevel.call(this, levelNdx, width, height, 1); 3100 }; 3101 3102 /** 3103 * @constructor 3104 * @extends {tcuTexture.TextureLevelPyramid} 3105 * @param {tcuTexture.TextureFormat} format 3106 * @param {number} width 3107 * @param {number} height 3108 * @param {number} numLayers 3109 */ 3110 tcuTexture.Texture2DArray = function(format, width, height, numLayers) { 3111 tcuTexture.TextureLevelPyramid.call(this, format, tcuTexture.computeMipPyramidLevels(width, height)); 3112 this.m_width = width; 3113 this.m_height = height; 3114 this.m_numLayers = numLayers; 3115 this.m_view = new tcuTexture.Texture2DArrayView(this.getNumLevels(), this.getLevels()); 3116 }; 3117 3118 tcuTexture.Texture2DArray.prototype = Object.create(tcuTexture.TextureLevelPyramid.prototype); 3119 tcuTexture.Texture2DArray.prototype.constructor = tcuTexture.Texture2DArray; 3120 /** @return {tcuTexture.Texture2DArrayView} */ 3121 tcuTexture.Texture2DArray.prototype.getView = function() { return this.m_view; }; 3122 3123 /** @return {number} */ 3124 tcuTexture.Texture2DArray.prototype.getWidth = function() { return this.m_width; }; 3125 3126 /** @return {number} */ 3127 tcuTexture.Texture2DArray.prototype.getHeight = function() { return this.m_height; }; 3128 3129 /** 3130 * @param {number} levelNdx 3131 */ 3132 tcuTexture.Texture2DArray.prototype.allocLevel = function(levelNdx) { 3133 DE_ASSERT(deMath.deInBounds32(levelNdx, 0, this.getNumLevels())); 3134 3135 var width = tcuTexture.getMipPyramidLevelSize(this.m_width, levelNdx); 3136 var height = tcuTexture.getMipPyramidLevelSize(this.m_height, levelNdx); 3137 3138 tcuTexture.TextureLevelPyramid.prototype.allocLevel.call(this, levelNdx, width, height, this.m_numLayers); 3139 }; 3140 3141 /** 3142 * @constructor 3143 * @extends {tcuTexture.TextureLevelPyramid} 3144 * @param {tcuTexture.TextureFormat} format 3145 * @param {number} width 3146 * @param {number} height 3147 * @param {number} depth 3148 */ 3149 tcuTexture.Texture3D = function(format, width, height, depth) { 3150 tcuTexture.TextureLevelPyramid.call(this, format, tcuTexture.computeMipPyramidLevels(width, height, depth)); 3151 this.m_width = width; 3152 this.m_height = height; 3153 this.m_depth = depth; 3154 this.m_view = new tcuTexture.Texture3DView(this.getNumLevels(), this.getLevels()); 3155 }; 3156 3157 tcuTexture.Texture3D.prototype = Object.create(tcuTexture.TextureLevelPyramid.prototype); 3158 tcuTexture.Texture3D.prototype.constructor = tcuTexture.Texture3D; 3159 3160 tcuTexture.Texture3D.prototype.getWidth = function() { return this.m_width; }; 3161 tcuTexture.Texture3D.prototype.getHeight = function() { return this.m_height; }; 3162 tcuTexture.Texture3D.prototype.getDepth = function() { return this.m_depth; }; 3163 tcuTexture.Texture3D.prototype.getView = function() { return this.m_view; }; 3164 /** 3165 * @param {number} baseLevel 3166 * @param {number} maxLevel 3167 * @return {tcuTexture.Texture3DView} 3168 */ 3169 tcuTexture.Texture3D.prototype.getSubView = function(baseLevel, maxLevel) { return this.m_view.getSubView(baseLevel, maxLevel); }; 3170 3171 /** 3172 * @param {number} levelNdx 3173 */ 3174 tcuTexture.Texture3D.prototype.allocLevel = function(levelNdx) { 3175 DE_ASSERT(deMath.deInBounds32(levelNdx, 0, this.getNumLevels())); 3176 3177 var width = tcuTexture.getMipPyramidLevelSize(this.m_width, levelNdx); 3178 var height = tcuTexture.getMipPyramidLevelSize(this.m_height, levelNdx); 3179 var depth = tcuTexture.getMipPyramidLevelSize(this.m_depth, levelNdx); 3180 3181 tcuTexture.TextureLevelPyramid.prototype.allocLevel.call(this, levelNdx, width, height, depth); 3182 }; 3183 3184 /** 3185 * @constructor 3186 * @param {number} numLevels 3187 * @param {Array<Array<tcuTexture.ConstPixelBufferAccess>>} levels 3188 */ 3189 tcuTexture.TextureCubeView = function(numLevels, levels) { 3190 this.m_numLevels = numLevels; 3191 this.m_levels = levels; 3192 }; 3193 3194 /** 3195 * @param {tcuTexture.Sampler} sampler 3196 * @param {Array<number>} texCoord 3197 * @param {number=} lod 3198 * @return {Array<number>} Pixel color 3199 */ 3200 tcuTexture.TextureCubeView.prototype.sample = function(sampler, texCoord, lod) { 3201 DE_ASSERT(sampler.compare == tcuTexture.CompareMode.COMPAREMODE_NONE); 3202 3203 // Computes (face, s, t). 3204 var coords = tcuTexture.getCubeFaceCoords(texCoord); 3205 if (sampler.seamlessCubeMap) 3206 return tcuTexture.sampleLevelArrayCubeSeamless(this.m_levels, this.m_numLevels, coords.face, sampler, coords.s, coords.t, 0 /* depth */, lod); 3207 else 3208 return tcuTexture.sampleLevelArray2D(this.m_levels[coords.face], this.m_numLevels, sampler, coords.s, coords.t, 0 /* depth */, lod); 3209 }; 3210 3211 /** 3212 * @param {tcuTexture.Sampler} sampler 3213 * @param {number} ref 3214 * @param {Array<number>} texCoord 3215 * @param {number} lod 3216 * @return {number} 3217 */ 3218 tcuTexture.TextureCubeView.prototype.sampleCompare = function(sampler, ref, texCoord, lod) { 3219 DE_ASSERT(sampler.compare != tcuTexture.CompareMode.COMPAREMODE_NONE); 3220 3221 // Computes (face, s, t). 3222 var coords = tcuTexture.getCubeFaceCoords(texCoord); 3223 if (sampler.seamlessCubeMap) 3224 return tcuTexture.sampleLevelArrayCubeSeamlessCompare(this.m_levels, this.m_numLevels, coords.face, sampler, ref, coords.s, coords.t, lod); 3225 else 3226 return tcuTexture.sampleLevelArray2DCompare(this.m_levels[coords.face], this.m_numLevels, sampler, ref, coords.s, coords.t, lod, [0, 0, 0]); 3227 }; 3228 3229 /** 3230 * @param {tcuTexture.CubeFace} face 3231 * @return {Array<tcuTexture.ConstPixelBufferAccess>} 3232 */ 3233 tcuTexture.TextureCubeView.prototype.getFaceLevels = function(face) { return this.m_levels[face]; }; 3234 /** @return {number} */ 3235 tcuTexture.TextureCubeView.prototype.getSize = function() { return this.m_numLevels > 0 ? this.m_levels[0][0].getWidth() : 0; }; 3236 3237 /** @return {number} */ 3238 tcuTexture.TextureCubeView.prototype.getNumLevels = function() { return this.m_numLevels; }; 3239 3240 /** 3241 * @param {number} ndx 3242 * @param {tcuTexture.CubeFace} face 3243 * @return {tcuTexture.ConstPixelBufferAccess} 3244 */ 3245 tcuTexture.TextureCubeView.prototype.getLevelFace = function(ndx, face) { 3246 assertMsgOptions(0 <= ndx && ndx < this.m_numLevels, '', false, true); 3247 return this.m_levels[face][ndx]; 3248 }; 3249 3250 /** 3251 * @param {number} baseLevel 3252 * @param {number} maxLevel 3253 * @return {tcuTexture.TextureCubeView} 3254 */ 3255 tcuTexture.TextureCubeView.prototype.getSubView = function(baseLevel, maxLevel) { 3256 var clampedBase = deMath.clamp(baseLevel, 0, this.m_numLevels - 1); 3257 var clampedMax = deMath.clamp(maxLevel, clampedBase, this.m_numLevels - 1); 3258 var numLevels = clampedMax - clampedBase + 1; 3259 var levels = []; 3260 for (var face in tcuTexture.CubeFace) 3261 levels.push(this.getFaceLevels(tcuTexture.CubeFace[face]).slice(clampedBase, numLevels)); 3262 3263 return new tcuTexture.TextureCubeView(numLevels, levels); 3264 }; 3265 3266 /** 3267 * @constructor 3268 * @param {tcuTexture.TextureFormat} format 3269 * @param {number} size 3270 */ 3271 tcuTexture.TextureCube = function(format, size) { 3272 this.m_format = format; 3273 this.m_size = size; 3274 this.m_data = []; 3275 this.m_data.length = Object.keys(tcuTexture.CubeFace).length; 3276 this.m_access = []; 3277 this.m_access.length = Object.keys(tcuTexture.CubeFace).length; 3278 3279 var numLevels = tcuTexture.computeMipPyramidLevels(this.m_size); 3280 var levels = []; 3281 levels.length = Object.keys(tcuTexture.CubeFace).length; 3282 3283 for (var face in tcuTexture.CubeFace) { 3284 this.m_data[tcuTexture.CubeFace[face]] = []; 3285 for (var i = 0; i < numLevels; i++) 3286 this.m_data[tcuTexture.CubeFace[face]].push(new tcuTexture.DeqpArrayBuffer()); 3287 this.m_access[tcuTexture.CubeFace[face]] = []; 3288 this.m_access[tcuTexture.CubeFace[face]].length = numLevels; 3289 levels[tcuTexture.CubeFace[face]] = this.m_access[tcuTexture.CubeFace[face]]; 3290 } 3291 3292 this.m_view = new tcuTexture.TextureCubeView(numLevels, levels); 3293 }; 3294 3295 /** @return {tcuTexture.TextureFormat} */ 3296 tcuTexture.TextureCube.prototype.getFormat = function() { return this.m_format; }; 3297 /** @return {number} */ 3298 tcuTexture.TextureCube.prototype.getSize = function() { return this.m_size; }; 3299 /** @return {tcuTexture.TextureCubeView} */ 3300 tcuTexture.TextureCube.prototype.getView = function() { return this.m_view; }; 3301 /** 3302 * @param {number} ndx Level index 3303 * @param {tcuTexture.CubeFace} face 3304 * @return {tcuTexture.PixelBufferAccess} 3305 */ 3306 tcuTexture.TextureCube.prototype.getLevelFace = function(ndx, face) { return this.m_access[face][ndx]; }; 3307 /** @return {number} */ 3308 tcuTexture.TextureCube.prototype.getNumLevels = function() { return this.m_access[0].length; }; 3309 3310 /** 3311 * @param {tcuTexture.Sampler} sampler 3312 * @param {Array<number>} texCoord 3313 * @param {number} lod 3314 * @return {Array<number>} Pixel color 3315 */ 3316 tcuTexture.TextureCube.prototype.sample = function(sampler, texCoord, lod) { 3317 return this.m_view.sample(sampler, texCoord, lod); 3318 }; 3319 3320 /** 3321 * @param {number} baseLevel 3322 * @param {number} maxLevel 3323 * @return {tcuTexture.TextureCubeView} 3324 */ 3325 tcuTexture.TextureCube.prototype.getSubView = function(baseLevel, maxLevel) { return this.m_view.getSubView(baseLevel, maxLevel); }; 3326 3327 /** 3328 * @param {tcuTexture.CubeFace} face 3329 * @param {number} levelNdx 3330 * @return {boolean} 3331 */ 3332 tcuTexture.TextureCube.prototype.isLevelEmpty = function(face, levelNdx) { 3333 return this.m_data[face][levelNdx].empty(); 3334 }; 3335 3336 /** 3337 * @param {tcuTexture.CubeFace} face 3338 * @param {number} levelNdx 3339 */ 3340 tcuTexture.TextureCube.prototype.allocLevel = function(face, levelNdx) { 3341 /** @const */ var size = tcuTexture.getMipPyramidLevelSize(this.m_size, levelNdx); 3342 /** @const*/ var dataSize = this.m_format.getPixelSize() * size * size; 3343 DE_ASSERT(this.isLevelEmpty(face, levelNdx)); 3344 3345 this.m_data[face][levelNdx].setStorage(dataSize); 3346 this.m_access[face][levelNdx] = new tcuTexture.PixelBufferAccess({ 3347 format: this.m_format, 3348 width: size, 3349 height: size, 3350 depth: 1, 3351 data: this.m_data[face][levelNdx].m_ptr 3352 }); 3353 }; 3354 3355 /** 3356 * @param {Array<number>} coords Cube coordinates 3357 * @return {tcuTexture.CubeFace} 3358 */ 3359 tcuTexture.selectCubeFace = function(coords) { 3360 var x = coords[0]; 3361 var y = coords[1]; 3362 var z = coords[2]; 3363 var ax = Math.abs(x); 3364 var ay = Math.abs(y); 3365 var az = Math.abs(z); 3366 3367 if (ay < ax && az < ax) 3368 return x >= 0 ? tcuTexture.CubeFace.CUBEFACE_POSITIVE_X : tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X; 3369 else if (ax < ay && az < ay) 3370 return y >= 0 ? tcuTexture.CubeFace.CUBEFACE_POSITIVE_Y : tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Y; 3371 else if (ax < az && ay < az) 3372 return z >= 0 ? tcuTexture.CubeFace.CUBEFACE_POSITIVE_Z : tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Z; 3373 else { 3374 // Some of the components are equal. Use tie-breaking rule. 3375 if (ax == ay) { 3376 if (ax < az) 3377 return z >= 0 ? tcuTexture.CubeFace.CUBEFACE_POSITIVE_Z : tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Z; 3378 else 3379 return x >= 0 ? tcuTexture.CubeFace.CUBEFACE_POSITIVE_X : tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X; 3380 } else if (ax == az) { 3381 if (az < ay) 3382 return y >= 0 ? tcuTexture.CubeFace.CUBEFACE_POSITIVE_Y : tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Y; 3383 else 3384 return z >= 0 ? tcuTexture.CubeFace.CUBEFACE_POSITIVE_Z : tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Z; 3385 } else if (ay == az) { 3386 if (ay < ax) 3387 return x >= 0 ? tcuTexture.CubeFace.CUBEFACE_POSITIVE_X : tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X; 3388 else 3389 return y >= 0 ? tcuTexture.CubeFace.CUBEFACE_POSITIVE_Y : tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Y; 3390 } else 3391 return x >= 0 ? tcuTexture.CubeFace.CUBEFACE_POSITIVE_X : tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X; 3392 } 3393 }; 3394 3395 /** 3396 * @param {tcuTexture.CubeFace} face 3397 * @param {Array<number>} coord Cube coordinates (Vec3) 3398 * @return {Array<number>} face coordinates (Vec2) 3399 */ 3400 tcuTexture.projectToFace = function(face, coord) { 3401 var rx = coord[0]; 3402 var ry = coord[1]; 3403 var rz = coord[2]; 3404 var sc = 0; 3405 var tc = 0; 3406 var ma = 0; 3407 3408 switch (face) { 3409 case tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X: sc = +rz; tc = -ry; ma = -rx; break; 3410 case tcuTexture.CubeFace.CUBEFACE_POSITIVE_X: sc = -rz; tc = -ry; ma = +rx; break; 3411 case tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Y: sc = +rx; tc = -rz; ma = -ry; break; 3412 case tcuTexture.CubeFace.CUBEFACE_POSITIVE_Y: sc = +rx; tc = +rz; ma = +ry; break; 3413 case tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Z: sc = -rx; tc = -ry; ma = -rz; break; 3414 case tcuTexture.CubeFace.CUBEFACE_POSITIVE_Z: sc = +rx; tc = -ry; ma = +rz; break; 3415 default: 3416 throw new Error('Unrecognized face ' + face); 3417 } 3418 3419 // Compute s, t 3420 var s = ((sc / ma) + 1) / 2; 3421 var t = ((tc / ma) + 1) / 2; 3422 3423 return [s, t]; 3424 }; 3425 3426 /** 3427 * @constructor 3428 * @param {tcuTexture.TextureFormat} format 3429 * @param {number=} width 3430 * @param {number=} height 3431 * @param {number=} depth 3432 */ 3433 tcuTexture.TextureLevel = function(format, width, height, depth) { 3434 this.m_format = format; 3435 this.m_width = width || 0; 3436 this.m_height = height || 0; 3437 this.m_depth = depth === undefined ? 1 : depth; 3438 this.m_data = new tcuTexture.DeqpArrayBuffer(); 3439 this.setSize(this.m_width, this.m_height, this.m_depth); 3440 }; 3441 3442 tcuTexture.TextureLevel.prototype.constructor = tcuTexture.TextureLevel; 3443 3444 /** 3445 * @param {tcuTexture.TextureFormat} format 3446 * @param {number=} width 3447 * @param {number=} height 3448 * @param {number=} depth 3449 */ 3450 tcuTexture.TextureLevel.prototype.setStorage = function(format, width, height, depth) { 3451 this.m_format = format; 3452 this.setSize(width, height, depth); 3453 }; 3454 3455 /** 3456 * @param {number=} width 3457 * @param {number=} height 3458 * @param {number=} depth 3459 */ 3460 tcuTexture.TextureLevel.prototype.setSize = function(width, height, depth) { 3461 var pixelSize = this.m_format.getPixelSize(); 3462 3463 this.m_width = width || 0; 3464 this.m_height = height || 0; 3465 this.m_depth = depth === undefined ? 1 : depth; 3466 3467 this.m_data.setStorage(this.m_width * this.m_height * this.m_depth * pixelSize); 3468 }; 3469 3470 /** 3471 * @return {tcuTexture.PixelBufferAccess} 3472 */ 3473 tcuTexture.TextureLevel.prototype.getAccess = function() { 3474 return new tcuTexture.PixelBufferAccess({ 3475 format: this.m_format, 3476 width: this.m_width, 3477 height: this.m_height, 3478 depth: this.m_depth, 3479 data: this.m_data.m_ptr 3480 }); 3481 3482 }; 3483 3484 /** 3485 * @return {number} 3486 */ 3487 tcuTexture.TextureLevel.prototype.getWidth = function() { 3488 return this.m_width; 3489 }; 3490 3491 /** 3492 * @return {number} 3493 */ 3494 tcuTexture.TextureLevel.prototype.getHeight = function() { 3495 return this.m_height; 3496 }; 3497 3498 /** 3499 * @return {number} 3500 */ 3501 tcuTexture.TextureLevel.prototype.getDepth = function() { 3502 return this.m_depth; 3503 }; 3504 3505 /** 3506 * @return {?tcuTexture.TextureFormat} 3507 */ 3508 tcuTexture.TextureLevel.prototype.getFormat = function() { 3509 return this.m_format; 3510 }; 3511 3512 /** 3513 * Checks if origCoords.coords is in bounds defined by size; if not, return a CubeFaceCoords with face set to the appropriate neighboring face and coords transformed accordingly. 3514 * \note If both x and y in origCoords.coords are out of bounds, this returns with face CUBEFACE_LAST, signifying that there is no unique neighboring face. 3515 * @param {tcuTexture.CubeFaceCoords} origCoords 3516 * @param {number} size 3517 * @return {tcuTexture.CubeFaceCoords} 3518 */ 3519 tcuTexture.remapCubeEdgeCoords = function(origCoords, size) { 3520 var uInBounds = deMath.deInBounds32(origCoords.s, 0, size); 3521 var vInBounds = deMath.deInBounds32(origCoords.t, 0, size); 3522 3523 if (uInBounds && vInBounds) 3524 return origCoords; 3525 3526 if (!uInBounds && !vInBounds) 3527 return null; 3528 3529 var coords = [ 3530 tcuTexture.wrap(tcuTexture.WrapMode.CLAMP_TO_BORDER, origCoords.s, size), 3531 tcuTexture.wrap(tcuTexture.WrapMode.CLAMP_TO_BORDER, origCoords.t, size)]; 3532 var canonizedCoords = []; 3533 3534 // Map the uv coordinates to canonized 3d coordinates. 3535 3536 switch (origCoords.face) { 3537 case tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X: canonizedCoords = [0, size - 1 - coords[1], coords[0]]; break; 3538 case tcuTexture.CubeFace.CUBEFACE_POSITIVE_X: canonizedCoords = [size - 1, size - 1 - coords[1], size - 1 - coords[0]]; break; 3539 case tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Y: canonizedCoords = [coords[0], 0, size - 1 - coords[1]]; break; 3540 case tcuTexture.CubeFace.CUBEFACE_POSITIVE_Y: canonizedCoords = [coords[0], size - 1, coords[1]]; break; 3541 case tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Z: canonizedCoords = [size - 1 - coords[0], size - 1 - coords[1], 0]; break; 3542 case tcuTexture.CubeFace.CUBEFACE_POSITIVE_Z: canonizedCoords = [coords[0], size - 1 - coords[1], size - 1]; break; 3543 default: throw new Error('Invalid cube face:' + origCoords.face); 3544 } 3545 3546 // Find an appropriate face to re-map the coordinates to. 3547 3548 if (canonizedCoords[0] == -1) 3549 return new tcuTexture.CubeFaceCoords(tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X, [canonizedCoords[2], size - 1 - canonizedCoords[1]]); 3550 3551 if (canonizedCoords[0] == size) 3552 return new tcuTexture.CubeFaceCoords(tcuTexture.CubeFace.CUBEFACE_POSITIVE_X, [size - 1 - canonizedCoords[2], size - 1 - canonizedCoords[1]]); 3553 3554 if (canonizedCoords[1] == -1) 3555 return new tcuTexture.CubeFaceCoords(tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Y, [canonizedCoords[0], size - 1 - canonizedCoords[2]]); 3556 3557 if (canonizedCoords[1] == size) 3558 return new tcuTexture.CubeFaceCoords(tcuTexture.CubeFace.CUBEFACE_POSITIVE_Y, [canonizedCoords[0], canonizedCoords[2]]); 3559 3560 if (canonizedCoords[2] == -1) 3561 return new tcuTexture.CubeFaceCoords(tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Z, [size - 1 - canonizedCoords[0], size - 1 - canonizedCoords[1]]); 3562 3563 if (canonizedCoords[2] == size) 3564 return new tcuTexture.CubeFaceCoords(tcuTexture.CubeFace.CUBEFACE_POSITIVE_Z, [canonizedCoords[0], size - 1 - canonizedCoords[1]]); 3565 3566 throw new Error('Cannot remap cube coordinates'); 3567 }; 3568 3569 /** 3570 * @constructor 3571 * @param {tcuTexture.ConstPixelBufferAccess} src 3572 */ 3573 tcuTexture.RGBA8View = function(src) { 3574 this.src = src; 3575 this.data = new Uint8Array(src.getBuffer(), src.m_offset); 3576 this.stride = src.getRowPitch(); 3577 this.width = src.getWidth(); 3578 this.height = src.getHeight(); 3579 this.pixelSize = src.getFormat().getPixelSize(); 3580 }; 3581 3582 /** 3583 * @return {tcuTexture.TextureFormat} 3584 */ 3585 tcuTexture.RGBA8View.prototype.getFormat = function() { return this.src.getFormat(); }; 3586 3587 /** 3588 * Read a pixel 3589 * @param {number} x 3590 * @param {number} y 3591 * @param {number=} numChannels 3592 * @return {Array<number>} 3593 */ 3594 tcuTexture.RGBA8View.prototype.read = function(x, y, numChannels) { 3595 numChannels = numChannels || 4; 3596 var offset = y * this.stride + x * this.pixelSize; 3597 /* Always return a vec4 */ 3598 var result = [0, 0, 0, 255]; 3599 for (var i = 0; i < numChannels; i++) 3600 result[i] = this.data[offset + i]; 3601 return result; 3602 }; 3603 3604 /** 3605 * Read a pixel into a Uint32 3606 * @param {number} x 3607 * @param {number} y 3608 * @return {number} 3609 */ 3610 tcuTexture.RGBA8View.prototype.readUintRGBA8 = function(x, y) { 3611 var offset = y * this.stride + x * this.pixelSize; 3612 return ((this.data[offset] & 0xff) << 24) + 3613 ((this.data[offset + 1] & 0xff) << 16) + 3614 ((this.data[offset + 2] & 0xff) << 8) + 3615 (this.data[offset + 3] & 0xff); 3616 }; 3617 3618 /** 3619 * Write a pixel 3620 * @param {number} x 3621 * @param {number} y 3622 * @param {Array<number>} value 3623 * @param {number=} numChannels 3624 */ 3625 tcuTexture.RGBA8View.prototype.write = function(x, y, value, numChannels) { 3626 numChannels = numChannels || 4; 3627 var offset = y * this.stride + x * this.pixelSize; 3628 for (var i = 0; i < numChannels; i++) 3629 this.data[offset + i] = value[i]; 3630 }; 3631 3632 tcuTexture.RGBA8View.prototype.getWidth = function() { return this.width; }; 3633 3634 tcuTexture.RGBA8View.prototype.getHeight = function() { return this.height; }; 3635 3636 });