1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES Utilities
3 * ------------------------------------------------
5 * Copyright 2014 The Android Open Source Project
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 goog.provide('functional.gles3.es3fPixelBufferObjectTest');
22 goog.require('framework.common.tcuImageCompare');
23 goog.require('framework.common.tcuTestCase');
24 goog.require('framework.common.tcuTexture');
25 goog.require('framework.common.tcuTextureUtil');
26 goog.require('framework.delibs.debase.deRandom');
27 goog.require('framework.delibs.debase.deString');
28 goog.require('framework.opengl.gluShaderProgram');
29 goog.require('framework.opengl.gluTextureUtil');
31 goog.scope(function() {
33 var es3fPixelBufferObjectTest = functional.gles3.es3fPixelBufferObjectTest;
34 var gluShaderProgram = framework.opengl.gluShaderProgram;
35 var tcuTestCase = framework.common.tcuTestCase;
36 var deRandom = framework.delibs.debase.deRandom;
37 var deString = framework.delibs.debase.deString;
38 var tcuTextureUtil = framework.common.tcuTextureUtil;
39 var tcuTexture = framework.common.tcuTexture;
40 var gluTextureUtil = framework.opengl.gluTextureUtil;
41 var tcuImageCompare = framework.common.tcuImageCompare;
43 var DE_ASSERT = function(x) {
45 throw new Error('Assert failed');
48 es3fPixelBufferObjectTest.DE_STATIC_ASSERT = function(expression) {
49 if (!expression) throw new Error('Assert failed');
53 es3fPixelBufferObjectTest.FramebufferType = {
54 FRAMEBUFFERTYPE_NATIVE: 0,
55 FRAMEBUFFERTYPE_RENDERBUFFER: 1
62 es3fPixelBufferObjectTest.TestSpec = function() { // This is originaly a struct
64 this.description = '';
65 this.useColorClear = false;
66 this.renderTriangles = false;
67 /** @type {es3fPixelBufferObjectTest.FramebufferType} */ this.framebufferType;
68 /** @type {number} */ this.renderbufferFormat;
73 * @extends {tcuTestCase.DeqpTest}
74 * @param {es3fPixelBufferObjectTest.TestSpec} spec
76 es3fPixelBufferObjectTest.ReadPixelsTest = function(spec) {
77 tcuTestCase.DeqpTest.call(this, spec.name, spec.description);
78 this.m_random = new deRandom.Random(deString.deStringHash(spec.name));
79 this.m_program = null;
80 this.m_framebuffeType = spec.framebufferType;
81 this.m_renderbufferFormat = spec.renderbufferFormat;
82 this.m_texChannelClass = undefined;
83 this.m_useColorClears = spec.useColorClear;
84 this.m_renderTriangles = spec.renderTriangles;
85 this.m_colorScale = 1.0;
87 if (this.m_framebuffeType === es3fPixelBufferObjectTest.FramebufferType.FRAMEBUFFERTYPE_NATIVE) {
88 this.m_colorScale = 1.0;
89 } else if (this.m_framebuffeType === es3fPixelBufferObjectTest.FramebufferType.FRAMEBUFFERTYPE_RENDERBUFFER) {
90 this.m_texChannelClass = tcuTexture.getTextureChannelClass(gluTextureUtil.mapGLInternalFormat(spec.renderbufferFormat).type);
91 switch (this.m_texChannelClass) {
92 case tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT:
93 this.m_colorScale = 1.0;
95 case tcuTexture.TextureChannelClass.SIGNED_INTEGER:
96 this.m_colorScale = 100.0;
98 case tcuTexture.TextureChannelClass.UNSIGNED_INTEGER:
99 this.m_colorScale = 100.0;
101 case tcuTexture.TextureChannelClass.FLOATING_POINT:
102 this.m_colorScale = 100.0;
112 es3fPixelBufferObjectTest.ReadPixelsTest.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
113 es3fPixelBufferObjectTest.ReadPixelsTest.prototype.constructor = es3fPixelBufferObjectTest.ReadPixelsTest;
115 es3fPixelBufferObjectTest.ReadPixelsTest.prototype.init = function() {
118 if (this.m_framebuffeType === es3fPixelBufferObjectTest.FramebufferType.FRAMEBUFFERTYPE_NATIVE)
120 else if (this.m_framebuffeType === es3fPixelBufferObjectTest.FramebufferType.FRAMEBUFFERTYPE_RENDERBUFFER) {
121 switch (this.m_texChannelClass) {
122 case tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT:
125 case tcuTexture.TextureChannelClass.SIGNED_INTEGER:
128 case tcuTexture.TextureChannelClass.UNSIGNED_INTEGER:
131 case tcuTexture.TextureChannelClass.FLOATING_POINT:
140 /** @type {string} */ var vertexShaderSource =
141 '#version 300 es\n' +
142 'in mediump vec3 a_position;\n' +
143 'in mediump vec4 a_color;\n' +
144 'uniform mediump float u_colorScale;\n' +
145 'out mediump vec4 v_color;\n' +
146 'void main(void)\n' +
148 '\tgl_Position = vec4(a_position, 1.0);\n' +
149 '\tv_color = u_colorScale * a_color;\n' +
152 /** @type {string} */ var fragmentShaderSource =
153 '#version 300 es\n' +
154 'in mediump vec4 v_color;\n' +
155 'layout (location = 0) out mediump ' +
158 'void main(void)\n' +
165 this.m_program = new gluShaderProgram.ShaderProgram(gl, gluShaderProgram.makeVtxFragSources(vertexShaderSource, fragmentShaderSource));
167 if (!this.m_program.isOk())
168 throw new Error('Compile failed. Program not created');
173 * @param {Array<number>} a
174 * @param {Array<number>} b
175 * @param {Array<number>} c
177 es3fPixelBufferObjectTest.ReadPixelsTest.prototype.renderTriangle = function(a, b, c) {
179 var positions = new Float32Array(36);
193 var colors = new Float32Array([
196 0.0, 0.0, 1.0, 1.0]);
198 gl.useProgram(this.m_program.getProgram());
199 assertMsgOptions(gl.getError() === gl.NO_ERROR, 'useProgram failed ', false, true);
201 /** @type {WebGLUniformLocation} */ var colorScaleLoc = gl.getUniformLocation(this.m_program.getProgram(), 'u_colorScale');
202 assertMsgOptions(colorScaleLoc != -1, 'Could not find u_colorScale ', false, true);
204 gl.uniform1f(colorScaleLoc, this.m_colorScale);
206 /** @type {number} */ var coordLoc = gl.getAttribLocation(this.m_program.getProgram(), 'a_position');
207 assertMsgOptions(coordLoc != -1, 'Could not find a_position ', false, true);
209 /** @type {number} */ var colorLoc = gl.getAttribLocation(this.m_program.getProgram(), 'a_color');
210 assertMsgOptions(colorLoc != -1, 'Could not find a_color ', false, true);
212 gl.enableVertexAttribArray(colorLoc);
213 assertMsgOptions(gl.getError() === gl.NO_ERROR, 'enableVertexAttribArray failed ', false, true);
214 gl.enableVertexAttribArray(coordLoc);
215 assertMsgOptions(gl.getError() === gl.NO_ERROR, 'enableVertexAttribArray failed ', false, true);
217 var pos = gl.createBuffer();
218 gl.bindBuffer(gl.ARRAY_BUFFER, pos);
219 gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);
220 gl.vertexAttribPointer(coordLoc, 3, gl.FLOAT, false, 0, 0);
222 var c = gl.createBuffer();
223 gl.bindBuffer(gl.ARRAY_BUFFER, c);
224 gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW);
225 gl.vertexAttribPointer(colorLoc, 4, gl.FLOAT, false, 0, 0);
227 gl.drawArrays(gl.TRIANGLES, 0, 3);
229 gl.disableVertexAttribArray(colorLoc);
230 gl.disableVertexAttribArray(coordLoc);
240 es3fPixelBufferObjectTest.ReadPixelsTest.prototype.clearColor = function(r, g, b, a) {
241 if (this.m_framebuffeType == es3fPixelBufferObjectTest.FramebufferType.FRAMEBUFFERTYPE_NATIVE) {
242 gl.clearColor(r, g, b, a);
243 gl.clear(gl.COLOR_BUFFER_BIT);
244 } else if (this.m_framebuffeType == es3fPixelBufferObjectTest.FramebufferType.FRAMEBUFFERTYPE_RENDERBUFFER) {
245 switch (this.m_texChannelClass) {
246 case tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT:
247 gl.clearColor(r, g, b, a);
248 gl.clear(gl.COLOR_BUFFER_BIT);
250 case tcuTexture.TextureChannelClass.SIGNED_INTEGER:
251 gl.clearBufferiv(gl.COLOR, 0, new Int32Array([r, g, b, a]));
253 case tcuTexture.TextureChannelClass.UNSIGNED_INTEGER:
254 gl.clearBufferuiv(gl.COLOR, 0, new Uint32Array([r, g, b, a]));
256 case tcuTexture.TextureChannelClass.FLOATING_POINT:
257 gl.clearBufferfv(gl.COLOR, 0, new Float32Array([r, g, b, a]));
267 es3fPixelBufferObjectTest.ReadPixelsTest.prototype.iterate = function() {
268 var width = gl.drawingBufferWidth;
269 var height = gl.drawingBufferHeight;
271 var framebuffer = null;
272 var renderbuffer = null;
274 switch (this.m_framebuffeType) {
275 case es3fPixelBufferObjectTest.FramebufferType.FRAMEBUFFERTYPE_NATIVE:
276 gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
278 case es3fPixelBufferObjectTest.FramebufferType.FRAMEBUFFERTYPE_RENDERBUFFER:
279 framebuffer = gl.createFramebuffer();
280 renderbuffer = gl.createRenderbuffer();
282 gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer);
283 gl.renderbufferStorage(gl.RENDERBUFFER, this.m_renderbufferFormat, width, height);
285 gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
286 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, renderbuffer);
290 this.clearColor(this.m_colorScale * 0.4, this.m_colorScale * 1.0, this.m_colorScale * 0.5, this.m_colorScale * 1.0);
292 if (this.m_useColorClears) {
293 /** @type {number} */ var maxClearCount = 10;
294 /** @type {number} */ var minClearCount = 6;
295 /** @type {number} */ var minClearSize = 15;
297 /** @type {number} */ var clearCount = this.m_random.getInt(minClearCount, maxClearCount);
299 for (var clearNdx = 0; clearNdx < clearCount; clearNdx++) {
300 /** @type {number} */ var clearX = this.m_random.getInt(0, width - minClearSize);
301 /** @type {number} */ var clearY = this.m_random.getInt(0, height - minClearSize);
303 /** @type {number} */ var clearWidth = this.m_random.getInt(minClearSize, width - clearX);
304 /** @type {number} */ var clearHeight = this.m_random.getInt(minClearSize, height - clearY);
306 /** @type {number} */ var clearRed = this.m_colorScale * this.m_random.getFloat();
307 /** @type {number} */ var clearGreen = this.m_colorScale * this.m_random.getFloat();
308 /** @type {number} */ var clearBlue = this.m_colorScale * this.m_random.getFloat();
309 /** @type {number} */ var clearAlpha = this.m_colorScale * (0.5 + 0.5 * this.m_random.getFloat());
311 gl.enable(gl.SCISSOR_TEST);
312 gl.scissor(clearX, clearY, clearWidth, clearHeight);
314 this.clearColor(clearRed, clearGreen, clearBlue, clearAlpha);
317 gl.disable(gl.SCISSOR_TEST);
321 if (this.m_renderTriangles) {
322 /** @type {number} */ var minTriangleCount = 4;
323 /** @type {number} */ var maxTriangleCount = 10;
325 /** @type {number} */ var triangleCount = this.m_random.getInt(minTriangleCount, maxTriangleCount);
327 for (var triangleNdx = 0; triangleNdx < triangleCount; triangleNdx++) {
328 /** @type {number} */ var x1 = 2.0 * this.m_random.getFloat() - 1.0;
329 /** @type {number} */ var y1 = 2.0 * this.m_random.getFloat() - 1.0;
330 /** @type {number} */ var z1 = 2.0 * this.m_random.getFloat() - 1.0;
332 /** @type {number} */ var x2 = 2.0 * this.m_random.getFloat() - 1.0;
333 /** @type {number} */ var y2 = 2.0 * this.m_random.getFloat() - 1.0;
334 /** @type {number} */ var z2 = 2.0 * this.m_random.getFloat() - 1.0;
336 /** @type {number} */ var x3 = 2.0 * this.m_random.getFloat() - 1.0;
337 /** @type {number} */ var y3 = 2.0 * this.m_random.getFloat() - 1.0;
338 /** @type {number} */ var z3 = 2.0 * this.m_random.getFloat() - 1.0;
340 this.renderTriangle([x1, y1, z1], [x2, y2, z2], [x3, y3, z3]);
344 /** @type {tcuTexture.TextureFormat} */ var readFormat;
345 /** @type {number} */ var readPixelsFormat;
346 /** @type {number} */ var readPixelsType;
347 /** @type {boolean} */ var floatCompare;
349 if (this.m_framebuffeType == es3fPixelBufferObjectTest.FramebufferType.FRAMEBUFFERTYPE_NATIVE) {
350 readFormat = gluTextureUtil.mapGLTransferFormat(gl.RGBA, gl.UNSIGNED_BYTE);
351 readPixelsFormat = gl.RGBA;
352 readPixelsType = gl.UNSIGNED_BYTE;
353 floatCompare = false;
354 } else if (this.m_framebuffeType == es3fPixelBufferObjectTest.FramebufferType.FRAMEBUFFERTYPE_RENDERBUFFER) {
355 switch (this.m_texChannelClass) {
356 case tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT:
357 readFormat = gluTextureUtil.mapGLTransferFormat(gl.RGBA, gl.UNSIGNED_BYTE);
358 readPixelsFormat = gl.RGBA;
359 readPixelsType = gl.UNSIGNED_BYTE;
362 case tcuTexture.TextureChannelClass.SIGNED_INTEGER:
363 readFormat = gluTextureUtil.mapGLTransferFormat(gl.RGBA_INTEGER, gl.INT);
364 readPixelsFormat = gl.RGBA_INTEGER;
365 readPixelsType = gl.INT;
366 floatCompare = false;
368 case tcuTexture.TextureChannelClass.UNSIGNED_INTEGER:
369 readFormat = gluTextureUtil.mapGLTransferFormat(gl.RGBA_INTEGER, gl.UNSIGNED_INT);
370 readPixelsFormat = gl.RGBA_INTEGER;
371 readPixelsType = gl.UNSIGNED_INT;
372 floatCompare = false;
374 case tcuTexture.TextureChannelClass.FLOATING_POINT:
375 readFormat = gluTextureUtil.mapGLTransferFormat(gl.RGBA, gl.FLOAT);
376 readPixelsFormat = gl.RGBA;
377 readPixelsType = gl.FLOAT;
383 readFormat = gluTextureUtil.mapGLTransferFormat(gl.RGBA, gl.FLOAT);
384 readPixelsFormat = gl.RGBA;
385 readPixelsType = gl.FLOAT;
390 readFormat = gluTextureUtil.mapGLTransferFormat(gl.RGBA, gl.FLOAT);
391 readPixelsFormat = gl.RGBA;
392 readPixelsType = gl.FLOAT;
397 var readReference = new tcuTexture.Texture2D(readFormat, width, height);
398 readReference.allocLevel(0);
400 var pixelBuffer = gl.createBuffer();
402 gl.bindBuffer(gl.PIXEL_PACK_BUFFER, pixelBuffer);
403 gl.bufferData(gl.PIXEL_PACK_BUFFER, readReference.getLevel(0).getDataSize(), gl.STREAM_READ);
404 gl.readPixels(0, 0, width, height, readPixelsFormat, readPixelsType, 0);
406 var bufferData = new Uint8Array(readReference.getLevel(0).getDataSize());
408 gl.getBufferSubData(gl.PIXEL_PACK_BUFFER, 0, bufferData);
410 var readResult = new tcuTexture.ConstPixelBufferAccess({
414 data: bufferData.buffer});
416 gl.bindBuffer(gl.PIXEL_PACK_BUFFER, null);
418 gl.readPixels(0, 0, width, height, readPixelsFormat, readPixelsType, readReference.getLevel(0).getDataPtr());
421 gl.deleteFramebuffer(framebuffer);
424 gl.deleteRenderbuffer(renderbuffer);
429 // When converting between integers and floats, certain GPUs might have different behaviors
430 // from javascript in rounding (up vs down). Increase tolerance to allow both behaviors.
431 // Detailed discussion in Mesa upstream can be found at:
432 // https://bugs.freedesktop.org/show_bug.cgi?id=89314.
434 switch (this.m_renderbufferFormat) {
438 threshold = [0.004, 0.004, 0.004, 0.0];
441 threshold = [0.0, 0.0, 0.0, 0.0];
444 isOk = tcuImageCompare.floatThresholdCompare('Result comparison', 'Result of read pixels to memory compared with result of read pixels to buffer', readReference.getLevel(0), readResult, threshold);
447 isOk = tcuImageCompare.intThresholdCompare('Result comparison', 'Result of read pixels to memory compared with result of read pixels to buffer', readReference.getLevel(0), readResult, [0, 0, 0, 0]);
449 gl.deleteBuffer(pixelBuffer);
451 assertMsgOptions(isOk, this.getDescription(), true, true);
453 return tcuTestCase.IterateResult.STOP;
456 es3fPixelBufferObjectTest.init = function() {
457 var state = tcuTestCase.runner;
458 /** @type {tcuTestCase.DeqpTest} */ var testGroup = state.testCases;
460 /** @type {tcuTestCase.DeqpTest} */ var nativeFramebufferGroup = tcuTestCase.newTest('native', 'Tests with reading from native framebuffer');
462 var nativeFramebufferTests = [{
464 description: 'Simple read pixels test with color clears',
466 renderTriangles: false,
467 framebufferType: es3fPixelBufferObjectTest.FramebufferType.FRAMEBUFFERTYPE_NATIVE,
468 renderbufferFormat: gl.NONE
471 description: 'Simple read pixels test rendering triangles',
472 useColorClear: false,
473 renderTriangles: true,
474 framebufferType: es3fPixelBufferObjectTest.FramebufferType.FRAMEBUFFERTYPE_NATIVE,
475 renderbufferFormat: gl.NONE
479 for (var testNdx = 0; testNdx < nativeFramebufferTests.length; testNdx++)
480 nativeFramebufferGroup.addChild(new es3fPixelBufferObjectTest.ReadPixelsTest(nativeFramebufferTests[testNdx]));
482 testGroup.addChild(nativeFramebufferGroup);
484 /** @type {tcuTestCase.DeqpTest} */ var renderbufferGroup = tcuTestCase.newTest('renderbuffer', 'Tests with reading from renderbuffer');
486 var renderbufferFormats = [
513 var renderbufferFormatsStr = [
539 es3fPixelBufferObjectTest.DE_STATIC_ASSERT(renderbufferFormatsStr.length == renderbufferFormats.length);
541 for (var formatNdx = 0; formatNdx < renderbufferFormats.length; formatNdx++) {
542 for (var trianglesClears = 0; trianglesClears < 2; trianglesClears++) {
543 var nameDescription = renderbufferFormatsStr[formatNdx] + '_' + (trianglesClears == 0 ? 'triangles' : 'clears');
544 var testSpec = new es3fPixelBufferObjectTest.TestSpec();
545 testSpec.name = nameDescription;
546 testSpec.description = nameDescription;
547 testSpec.useColorClear = trianglesClears == 1;
548 testSpec.renderTriangles = trianglesClears == 0;
549 testSpec.framebufferType = es3fPixelBufferObjectTest.FramebufferType.FRAMEBUFFERTYPE_RENDERBUFFER;
550 testSpec.renderbufferFormat = renderbufferFormats[formatNdx];
552 renderbufferGroup.addChild(new es3fPixelBufferObjectTest.ReadPixelsTest(testSpec));
556 testGroup.addChild(renderbufferGroup);
559 es3fPixelBufferObjectTest.run = function(context) {
561 //Set up Test Root parameters
562 var testName = 'pixel_buffer_object';
563 var testDescription = 'Pixel Buffer Object Tests';
564 var state = tcuTestCase.runner;
566 state.testName = testName;
567 state.testCases = tcuTestCase.newTest(testName, testDescription, null);
569 //Set up name and description of this test series.
570 setCurrentTestName(testName);
571 description(testDescription);
575 es3fPixelBufferObjectTest.init();
577 tcuTestCase.runTestCases();
580 bufferedLogToConsole(err);
581 tcuTestCase.runner.terminate();