+ * @param context Rendering context
+ */
+SparseTexture2LookupTestCase::SparseTexture2LookupTestCase(deqp::Context& context)
+ : SparseTexture2CommitmentTestCase(context, "SparseTexture2Lookup",
+ "Verifies if sparse texture lookup functions for GLSL works as expected")
+{
+ /* Left blank intentionally */
+}
+
+/** Initializes the test group contents. */
+void SparseTexture2LookupTestCase::init()
+{
+ SparseTextureCommitmentTestCase::init();
+ mSupportedTargets.push_back(GL_TEXTURE_2D_MULTISAMPLE);
+ mSupportedTargets.push_back(GL_TEXTURE_2D_MULTISAMPLE_ARRAY);
+
+ mSupportedInternalFormats.push_back(GL_DEPTH_COMPONENT16);
+
+ FunctionToken f;
+ f = FunctionToken("sparseTextureARB", "");
+ f.allowedTargets.insert(GL_TEXTURE_2D);
+ f.allowedTargets.insert(GL_TEXTURE_2D_ARRAY);
+ f.allowedTargets.insert(GL_TEXTURE_CUBE_MAP);
+ f.allowedTargets.insert(GL_TEXTURE_CUBE_MAP_ARRAY);
+ f.allowedTargets.insert(GL_TEXTURE_3D);
+ f.allowedTargets.insert(GL_TEXTURE_RECTANGLE);
+ mFunctions.push_back(f);
+
+ f = FunctionToken("sparseTextureLodARB", "<LOD_DEF>");
+ f.allowedTargets.insert(GL_TEXTURE_2D);
+ f.allowedTargets.insert(GL_TEXTURE_2D_ARRAY);
+ f.allowedTargets.insert(GL_TEXTURE_CUBE_MAP);
+ f.allowedTargets.insert(GL_TEXTURE_CUBE_MAP_ARRAY);
+ f.allowedTargets.insert(GL_TEXTURE_3D);
+ mFunctions.push_back(f);
+
+ f = FunctionToken("sparseTextureOffsetARB", ", ivec<OFFSET_DIM>(0)");
+ f.allowedTargets.insert(GL_TEXTURE_2D);
+ f.allowedTargets.insert(GL_TEXTURE_2D_ARRAY);
+ f.allowedTargets.insert(GL_TEXTURE_3D);
+ f.allowedTargets.insert(GL_TEXTURE_RECTANGLE);
+ mFunctions.push_back(f);
+
+ f = FunctionToken("sparseTexelFetchARB", "<LOD_DEF>");
+ f.allowedTargets.insert(GL_TEXTURE_2D);
+ f.allowedTargets.insert(GL_TEXTURE_2D_ARRAY);
+ f.allowedTargets.insert(GL_TEXTURE_3D);
+ f.allowedTargets.insert(GL_TEXTURE_RECTANGLE);
+ f.allowedTargets.insert(GL_TEXTURE_2D_MULTISAMPLE);
+ f.allowedTargets.insert(GL_TEXTURE_2D_MULTISAMPLE_ARRAY);
+ mFunctions.push_back(f);
+
+ f = FunctionToken("sparseTexelFetchOffsetARB", "<LOD_DEF>, ivec<OFFSET_DIM>(0)");
+ f.allowedTargets.insert(GL_TEXTURE_2D);
+ f.allowedTargets.insert(GL_TEXTURE_2D_ARRAY);
+ f.allowedTargets.insert(GL_TEXTURE_3D);
+ f.allowedTargets.insert(GL_TEXTURE_RECTANGLE);
+ mFunctions.push_back(f);
+
+ f = FunctionToken("sparseTextureLodOffsetARB", "<LOD_DEF>, ivec<OFFSET_DIM>(0)");
+ f.allowedTargets.insert(GL_TEXTURE_2D);
+ f.allowedTargets.insert(GL_TEXTURE_2D_ARRAY);
+ f.allowedTargets.insert(GL_TEXTURE_3D);
+ mFunctions.push_back(f);
+
+ f = FunctionToken("sparseTextureGradARB", ", vec<OFFSET_DIM>(0), vec<OFFSET_DIM>(0)");
+ f.allowedTargets.insert(GL_TEXTURE_2D);
+ f.allowedTargets.insert(GL_TEXTURE_2D_ARRAY);
+ f.allowedTargets.insert(GL_TEXTURE_CUBE_MAP);
+ f.allowedTargets.insert(GL_TEXTURE_CUBE_MAP_ARRAY);
+ f.allowedTargets.insert(GL_TEXTURE_3D);
+ f.allowedTargets.insert(GL_TEXTURE_RECTANGLE);
+ mFunctions.push_back(f);
+
+ f = FunctionToken("sparseTextureGradOffsetARB", ", vec<OFFSET_DIM>(0), vec<OFFSET_DIM>(0), ivec<OFFSET_DIM>(0)");
+ f.allowedTargets.insert(GL_TEXTURE_2D);
+ f.allowedTargets.insert(GL_TEXTURE_2D_ARRAY);
+ f.allowedTargets.insert(GL_TEXTURE_3D);
+ f.allowedTargets.insert(GL_TEXTURE_RECTANGLE);
+ mFunctions.push_back(f);
+
+ f = FunctionToken("sparseTextureGatherARB", "<REFZ_DEF>");
+ f.allowedTargets.insert(GL_TEXTURE_2D);
+ f.allowedTargets.insert(GL_TEXTURE_2D_ARRAY);
+ f.allowedTargets.insert(GL_TEXTURE_CUBE_MAP);
+ f.allowedTargets.insert(GL_TEXTURE_CUBE_MAP_ARRAY);
+ f.allowedTargets.insert(GL_TEXTURE_RECTANGLE);
+ mFunctions.push_back(f);
+
+ f = FunctionToken("sparseTextureGatherOffsetARB", "<REFZ_DEF>, ivec<OFFSET_DIM>(0)");
+ f.allowedTargets.insert(GL_TEXTURE_2D);
+ f.allowedTargets.insert(GL_TEXTURE_2D_ARRAY);
+ f.allowedTargets.insert(GL_TEXTURE_RECTANGLE);
+ mFunctions.push_back(f);
+
+ f = FunctionToken("sparseTextureGatherOffsetsARB", "<REFZ_DEF>, offsetsArray");
+ f.allowedTargets.insert(GL_TEXTURE_2D);
+ f.allowedTargets.insert(GL_TEXTURE_2D_ARRAY);
+ f.allowedTargets.insert(GL_TEXTURE_RECTANGLE);
+ mFunctions.push_back(f);
+
+ f = FunctionToken("sparseImageLoadARB", "");
+ f.allowedTargets.insert(GL_TEXTURE_2D);
+ f.allowedTargets.insert(GL_TEXTURE_2D_ARRAY);
+ f.allowedTargets.insert(GL_TEXTURE_CUBE_MAP);
+ f.allowedTargets.insert(GL_TEXTURE_CUBE_MAP_ARRAY);
+ f.allowedTargets.insert(GL_TEXTURE_3D);
+ f.allowedTargets.insert(GL_TEXTURE_RECTANGLE);
+ f.allowedTargets.insert(GL_TEXTURE_2D_MULTISAMPLE);
+ f.allowedTargets.insert(GL_TEXTURE_2D_MULTISAMPLE_ARRAY);
+ mFunctions.push_back(f);
+}
+
+/** Executes test iteration.
+ *
+ * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
+ */
+tcu::TestNode::IterateResult SparseTexture2LookupTestCase::iterate()
+{
+ if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_sparse_texture2"))
+ {
+ m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported");
+ return STOP;
+ }
+
+ const Functions& gl = m_context.getRenderContext().getFunctions();
+
+ bool result = true;
+
+ GLuint texture;
+
+ for (std::vector<glw::GLint>::const_iterator iter = mSupportedTargets.begin(); iter != mSupportedTargets.end();
+ ++iter)
+ {
+ const GLint& target = *iter;
+
+ for (std::vector<glw::GLint>::const_iterator formIter = mSupportedInternalFormats.begin();
+ formIter != mSupportedInternalFormats.end(); ++formIter)
+ {
+ const GLint& format = *formIter;
+
+ if (!caseAllowed(target, format))
+ continue;
+
+ for (std::vector<FunctionToken>::const_iterator tokIter = mFunctions.begin(); tokIter != mFunctions.end();
+ ++tokIter)
+ {
+ // Check if target is allowed for current lookup function
+ FunctionToken funcToken = *tokIter;
+ if (!funcAllowed(target, format, funcToken))
+ continue;
+
+ mLog.str("");
+ mLog << "Testing sparse texture lookup functions for target: " << target << ", format: " << format
+ << " - ";
+
+ sparseAllocateTexture(gl, target, format, texture, 3);
+ if (format == GL_DEPTH_COMPONENT16)
+ setupDepthMode(gl, target, texture);
+
+ for (int l = 0; l < mState.levels; ++l)
+ {
+ if (commitTexturePage(gl, target, format, texture, l))
+ {
+ writeDataToTexture(gl, target, format, texture, l);
+ result = result && verifyLookupTextureData(gl, target, format, texture, l, funcToken);
+ }
+
+ if (!result)
+ break;
+ }
+
+ Texture::Delete(gl, texture);
+
+ if (!result)
+ {
+ m_testCtx.getLog() << tcu::TestLog::Message << mLog.str() << "Fail" << tcu::TestLog::EndMessage;
+ m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
+ return STOP;
+ }
+ }
+ }
+ }
+
+ m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
+ return STOP;
+}
+
+/** Create set of token strings fit to lookup functions verifying shader
+ *
+ * @param target Target for which texture is binded
+ * @param format Texture internal format
+ * @param level Texture mipmap level
+ * @param sample Texture sample number
+ * @param funcToken Texture lookup function structure
+ *
+ * @return Returns extended token strings structure.
+ */
+SparseTexture2LookupTestCase::TokenStringsExt SparseTexture2LookupTestCase::createLookupShaderTokens(
+ GLint target, GLint format, GLint level, GLint sample, FunctionToken& funcToken)
+{
+ std::string funcName = funcToken.name;
+
+ TokenStringsExt s;
+
+ std::string inputType;
+ std::string samplerSufix;
+
+ if (funcName == "sparseImageLoadARB")
+ inputType = "image";
+ else
+ inputType = "sampler";
+
+ // Copy data from TokenStrings to TokenStringsExt
+ TokenStrings ss = createShaderTokens(target, format, sample, "image", inputType);
+ s.epsilon = ss.epsilon;
+ s.format = ss.format;
+ s.inputType = ss.inputType;
+ s.outputType = ss.outputType;
+ s.pointDef = ss.pointDef;
+ s.pointType = ss.pointType;
+ s.resultDefault = ss.resultDefault;
+ s.resultExpected = ss.resultExpected;
+ s.returnType = ss.returnType;
+ s.sampleDef = ss.sampleDef;
+
+ // Set format definition for image input types
+ if (inputType == "image")
+ s.formatDef = ", " + s.format;
+
+ // Set tokens for depth texture format
+ if (format == GL_DEPTH_COMPONENT16)
+ {
+ s.refZDef = ", 0.5";
+
+ if (inputType == "sampler" && target != GL_TEXTURE_3D && target != GL_TEXTURE_2D_MULTISAMPLE &&
+ target != GL_TEXTURE_2D_MULTISAMPLE_ARRAY)
+ {
+ s.inputType = s.inputType + "Shadow";
+ }
+ }
+
+ // Set coord type, coord definition and offset vector dimensions
+ s.coordType = "vec2";
+ s.offsetDim = "2";
+ if (target == GL_TEXTURE_2D_ARRAY)
+ {
+ s.coordType = "vec3";
+ }
+ else if (target == GL_TEXTURE_3D)
+ {
+ s.coordType = "vec3";
+ s.offsetDim = "3";
+ }
+ else if (target == GL_TEXTURE_CUBE_MAP)
+ {
+ s.coordType = "vec3";
+ s.offsetDim = "3";
+ }
+ else if (target == GL_TEXTURE_CUBE_MAP_ARRAY)
+ {
+ s.coordType = "vec4";
+ s.coordDef = "gl_WorkGroupID.x, gl_WorkGroupID.y, gl_WorkGroupID.z % 6, floor(gl_WorkGroupID.z / 6)";
+ s.offsetDim = "3";
+ }
+ else if (target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY)
+ {
+ s.coordType = "vec3";
+ }
+
+ if ((target == GL_TEXTURE_CUBE_MAP || target == GL_TEXTURE_CUBE_MAP_ARRAY) &&
+ funcName.find("Fetch", 0) == std::string::npos)
+ {
+ s.cubeMapCoordDef = " if (point.z == 0) coord.xyz = vec3(1, coord.y * 2 - 1, -coord.x * 2 + 1);\n"
+ " if (point.z == 1) coord.xyz = vec3(-1, coord.y * 2 - 1, coord.x * 2 - 1);\n"
+ " if (point.z == 2) coord.xyz = vec3(coord.x * 2 - 1, 1, coord.y * 2 - 1);\n"
+ " if (point.z == 3) coord.xyz = vec3(coord.x * 2 - 1, -1, -coord.y * 2 + 1);\n"
+ " if (point.z == 4) coord.xyz = vec3(coord.x * 2 - 1, coord.y * 2 - 1, 1);\n"
+ " if (point.z == 5) coord.xyz = vec3(-coord.x * 2 + 1, coord.y * 2 - 1, -1);\n";
+ }
+
+ if (s.coordDef.empty())
+ s.coordDef = s.pointDef;
+
+ // Set expected result vector, component definition and offset array definition for gather functions
+ if (funcName.find("Gather", 0) != std::string::npos)
+ {
+ if (funcName.find("GatherOffsets", 0) != std::string::npos)
+ {
+ s.offsetArrayDef = " ivec<OFFSET_DIM> offsetsArray[4];\n"
+ " offsetsArray[0] = ivec<OFFSET_DIM>(0);\n"
+ " offsetsArray[1] = ivec<OFFSET_DIM>(0);\n"
+ " offsetsArray[2] = ivec<OFFSET_DIM>(0);\n"
+ " offsetsArray[3] = ivec<OFFSET_DIM>(0);\n";
+ }
+
+ if (format != GL_DEPTH_COMPONENT16)
+ s.componentDef = ", 0";
+ s.resultExpected = "(1, 1, 1, 1)";
+ }
+ // Extend coord type dimension and coord vector definition if shadow sampler and non-cube map array target selected
+ // Set component definition to red component
+ else if (format == GL_DEPTH_COMPONENT16)
+ {
+ if (target != GL_TEXTURE_CUBE_MAP_ARRAY)
+ {
+ if (s.coordType == "vec2")
+ s.coordType = "vec3";
+ else if (s.coordType == "vec3")
+ s.coordType = "vec4";
+ s.coordDef += s.refZDef;
+ }
+ else
+ funcToken.arguments += s.refZDef;
+
+ s.componentDef = ".r";
+ }
+
+ // Set level of details definition
+ if (target != GL_TEXTURE_RECTANGLE && target != GL_TEXTURE_2D_MULTISAMPLE &&
+ target != GL_TEXTURE_2D_MULTISAMPLE_ARRAY)
+ {
+ s.lodDef = ", " + de::toString(level);
+ }
+
+ // Set proper coord vector
+ if (target == GL_TEXTURE_RECTANGLE || funcName.find("Fetch") != std::string::npos ||
+ funcName.find("ImageLoad") != std::string::npos)
+ {
+ s.pointCoord = "icoord";
+ }
+ else
+ s.pointCoord = "coord";
+
+ // Set size vector definition
+ if (format != GL_DEPTH_COMPONENT16 || funcName.find("Gather", 0) != std::string::npos)
+ {
+ if (s.coordType == "vec2")
+ s.sizeDef = "<TEX_WIDTH>, <TEX_HEIGHT>";
+ else if (s.coordType == "vec3")
+ s.sizeDef = "<TEX_WIDTH>, <TEX_HEIGHT>, <TEX_DEPTH>";
+ else if (s.coordType == "vec4")
+ s.sizeDef = "<TEX_WIDTH>, <TEX_HEIGHT>, floor(<TEX_DEPTH> / 6), 6";
+ }
+ // Set size vector for shadow samplers and non-gether functions selected
+ else
+ {
+ if (s.coordType == "vec3")
+ s.sizeDef = "<TEX_WIDTH>, <TEX_HEIGHT>, 1";
+ else if (s.coordType == "vec4")
+ s.sizeDef = "<TEX_WIDTH>, <TEX_HEIGHT>, <TEX_DEPTH>, 1";
+ }
+
+ return s;
+}
+
+/** Check if specific combination of target and format is allowed
+ *
+ * @param target Target for which texture is binded
+ * @param format Texture internal format
+ *
+ * @return Returns true if target/format combination is allowed, false otherwise.
+ */
+bool SparseTexture2LookupTestCase::caseAllowed(GLint target, GLint format)
+{
+ DE_UNREF(target);
+
+ // As shaders do not support some texture formats it is necessary to exclude them.
+ if (format == GL_RGB565 || format == GL_RGB10_A2UI || format == GL_RGB9_E5)
+ {
+ return false;
+ }
+
+ if ((target == GL_TEXTURE_2D_MULTISAMPLE || target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY || target == GL_TEXTURE_3D) &&
+ (format == GL_DEPTH_COMPONENT16))
+ {
+ return false;
+ }
+
+ return true;
+}
+
+/** Check if specific lookup function is allowed for specific target and format
+ *
+ * @param target Target for which texture is binded
+ * @param format Texture internal format
+ * @param sample Multisample texture sample number
+ * @param funcToken Texture lookup function structure
+ *
+ * @return Returns true if target/format combination is allowed, false otherwise.
+ */
+bool SparseTexture2LookupTestCase::funcAllowed(GLint target, GLint format, FunctionToken& funcToken)
+{
+ if (funcToken.allowedTargets.find(target) == funcToken.allowedTargets.end())
+ return false;
+
+ if (format == GL_DEPTH_COMPONENT16)
+ {
+ if (funcToken.name == "sparseTextureLodARB" || funcToken.name == "sparseTextureLodOffsetARB")
+ {
+ if (target != GL_TEXTURE_2D)
+ return false;
+ }
+ else if (funcToken.name == "sparseTextureOffsetARB" || funcToken.name == "sparseTextureGradOffsetARB" ||
+ funcToken.name == "sparseTextureGatherOffsetARB" || funcToken.name == "sparseTextureGatherOffsetsARB")
+ {
+ if (target != GL_TEXTURE_2D && target != GL_TEXTURE_2D_ARRAY && target != GL_TEXTURE_RECTANGLE)
+ {
+ return false;
+ }
+ }
+ else if (funcToken.name == "sparseTexelFetchARB" || funcToken.name == "sparseTexelFetchOffsetARB")
+ {
+ return false;
+ }
+ else if (funcToken.name == "sparseTextureGradARB")
+ {
+ if (target == GL_TEXTURE_CUBE_MAP_ARRAY)
+ return false;
+ }
+ else if (funcToken.name == "sparseImageLoadARB")
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/** Writing data to generated texture using compute shader
+ *
+ * @param gl GL API functions
+ * @param target Target for which texture is binded
+ * @param format Texture internal format
+ * @param texture Texture object
+ *
+ * @return Returns true if no error occurred, otherwise throws an exception.
+ */
+bool SparseTexture2LookupTestCase::writeDataToTexture(const Functions& gl, GLint target, GLint format, GLuint& texture,
+ GLint level)
+{
+ mLog << "Fill Texture with shader [level: " << level << "] - ";
+
+ if (level > mState.levels - 1)
+ TCU_FAIL("Invalid level");
+
+ GLint width;
+ GLint height;
+ GLint depth;
+ SparseTextureUtils::getTextureLevelSize(target, mState, level, width, height, depth);
+
+ if (width > 0 && height > 0 && depth >= mState.minDepth)
+ {
+ if (target == GL_TEXTURE_CUBE_MAP)
+ depth = depth * 6;
+
+ GLint texSize = width * height * depth * mState.format.getPixelSize();
+
+ std::vector<GLubyte> vecData;
+ vecData.resize(texSize);
+ GLubyte* data = vecData.data();
+
+ deMemset(data, 255, texSize);
+
+ for (GLint sample = 0; sample < mState.samples; ++sample)
+ {
+ std::string shader = compute_textureFill;
+
+ // Adjust shader source to texture format
+ TokenStrings s = createShaderTokens(target, format, sample);
+
+ replaceToken("<INPUT_TYPE>", s.inputType.c_str(), shader);
+ replaceToken("<POINT_TYPE>", s.pointType.c_str(), shader);
+ replaceToken("<POINT_DEF>", s.pointDef.c_str(), shader);
+ replaceToken("<RETURN_TYPE>", s.returnType.c_str(), shader);
+ replaceToken("<RESULT_EXPECTED>", s.resultExpected.c_str(), shader);
+ replaceToken("<SAMPLE_DEF>", s.sampleDef.c_str(), shader);
+
+ ProgramSources sources;
+ sources << ComputeSource(shader);
+
+ GLint convFormat = format;
+ if (format == GL_DEPTH_COMPONENT16)
+ convFormat = GL_R16;
+
+ // Build and run shader
+ ShaderProgram program(m_context.getRenderContext(), sources);
+ if (program.isOk())
+ {
+ gl.useProgram(program.getProgram());
+ GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram");
+ gl.bindImageTexture(0 /* unit */, texture, level /* level */, GL_FALSE /* layered */, 0 /* layer */,
+ GL_WRITE_ONLY, convFormat);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "glBindImageTexture");
+ gl.uniform1i(1, 0 /* image_unit */);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform1i");
+ gl.dispatchCompute(width, height, depth);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "glDispatchCompute");
+ gl.memoryBarrier(GL_ALL_BARRIER_BITS);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "glMemoryBarrier");
+ }
+ else
+ {
+ mLog << "Compute shader compilation failed (writing) for target: " << target << ", format: " << format
+ << ", sample: " << sample << ", infoLog: " << program.getShaderInfo(SHADERTYPE_COMPUTE).infoLog
+ << ", shaderSource: " << shader.c_str() << " - ";
+ }
+ }
+ }
+
+ return true;
+}
+
+/** Setup depth compare mode and compare function for depth texture
+ *
+ * @param gl GL API functions
+ * @param target Target for which texture is binded
+ * @param texture Texture object
+ */
+void SparseTexture2LookupTestCase::setupDepthMode(const Functions& gl, GLint target, GLuint& texture)
+{
+ Texture::Bind(gl, texture, target);
+ gl.texParameteri(target, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "glTexParameteri");
+ gl.texParameteri(target, GL_TEXTURE_COMPARE_FUNC, GL_ALWAYS);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "glTexParameteri");
+}
+
+/** Verify if data stored in texture is as expected
+ *
+ * @param gl GL API functions
+ * @param target Target for which texture is binded
+ * @param format Texture internal format
+ * @param texture Texture object
+ * @param level Texture mipmap level
+ * @param funcToken Lookup function tokenize structure
+ *
+ * @return Returns true if data is as expected, false if not, throws an exception if error occurred.
+ */
+bool SparseTexture2LookupTestCase::verifyLookupTextureData(const Functions& gl, GLint target, GLint format,
+ GLuint& texture, GLint level, FunctionToken& funcToken)
+{
+ mLog << "Verify Lookup Texture Data [function: " << funcToken.name << ", level: " << level << "] - ";
+
+ if (level > mState.levels - 1)
+ TCU_FAIL("Invalid level");
+
+ GLint width;
+ GLint height;
+ GLint depth;
+ SparseTextureUtils::getTextureLevelSize(target, mState, level, width, height, depth);
+
+ //Committed region is limited to 1/2 of width
+ GLint widthCommitted = width / 2;
+
+ if (widthCommitted == 0 || height == 0 || depth < mState.minDepth)
+ return true;
+
+ bool result = true;
+
+ if (target == GL_TEXTURE_CUBE_MAP)
+ depth = depth * 6;
+
+ GLint texSize = width * height * depth;
+
+ std::vector<GLubyte> vecExpData;
+ std::vector<GLubyte> vecOutData;
+ vecExpData.resize(texSize);
+ vecOutData.resize(texSize);
+ GLubyte* exp_data = vecExpData.data();
+ GLubyte* out_data = vecOutData.data();
+
+ // Expected data is 255 because
+ deMemset(exp_data, 255, texSize);
+
+ // Make token copy to work on
+ FunctionToken f = funcToken;
+
+ // Create verifying texture
+ GLint verifyTarget;
+ if (target == GL_TEXTURE_2D_MULTISAMPLE)
+ verifyTarget = GL_TEXTURE_2D;
+ else
+ verifyTarget = GL_TEXTURE_2D_ARRAY;
+
+ GLuint verifyTexture;
+ Texture::Generate(gl, verifyTexture);
+ Texture::Bind(gl, verifyTexture, verifyTarget);
+ Texture::Storage(gl, verifyTarget, 1, GL_R8, width, height, depth);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "Texture::Storage");
+
+ for (int sample = 0; sample < mState.samples; ++sample)
+ {
+ deMemset(out_data, 0, texSize);
+
+ Texture::Bind(gl, verifyTexture, verifyTarget);
+ Texture::SubImage(gl, verifyTarget, 0, 0, 0, 0, width, height, depth, GL_RED, GL_UNSIGNED_BYTE,
+ (GLvoid*)out_data);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "Texture::SubImage");
+
+ std::string shader = compute_lookupVerify;
+
+ // Adjust shader source to texture format
+ TokenStringsExt s = createLookupShaderTokens(target, format, level, sample, f);
+
+ replaceToken("<FUNCTION>", f.name.c_str(), shader);
+ replaceToken("<ARGUMENTS>", f.arguments.c_str(), shader);
+
+ replaceToken("<OUTPUT_TYPE>", s.outputType.c_str(), shader);
+ replaceToken("<INPUT_TYPE>", s.inputType.c_str(), shader);
+ replaceToken("<SIZE_DEF>", s.sizeDef.c_str(), shader);
+ replaceToken("<LOD_DEF>", s.lodDef.c_str(), shader);
+ replaceToken("<COORD_TYPE>", s.coordType.c_str(), shader);
+ replaceToken("<COORD_DEF>", s.coordDef.c_str(), shader);
+ replaceToken("<POINT_TYPE>", s.pointType.c_str(), shader);
+ replaceToken("<POINT_DEF>", s.pointDef.c_str(), shader);
+ replaceToken("<RETURN_TYPE>", s.returnType.c_str(), shader);
+ replaceToken("<RESULT_EXPECTED>", s.resultExpected.c_str(), shader);
+ replaceToken("<EPSILON>", s.epsilon.c_str(), shader);
+ replaceToken("<SAMPLE_DEF>", s.sampleDef.c_str(), shader);
+ replaceToken("<REFZ_DEF>", s.refZDef.c_str(), shader);
+ replaceToken("<POINT_COORD>", s.pointCoord.c_str(), shader);
+ replaceToken("<COMPONENT_DEF>", s.componentDef.c_str(), shader);
+ replaceToken("<CUBE_MAP_COORD_DEF>", s.cubeMapCoordDef.c_str(), shader);
+ replaceToken("<OFFSET_ARRAY_DEF>", s.offsetArrayDef.c_str(), shader);
+ replaceToken("<FORMAT_DEF>", s.formatDef.c_str(), shader);
+ replaceToken("<OFFSET_DIM>", s.offsetDim.c_str(), shader);
+
+ replaceToken("<TEX_WIDTH>", de::toString(width).c_str(), shader);
+ replaceToken("<TEX_HEIGHT>", de::toString(height).c_str(), shader);
+ replaceToken("<TEX_DEPTH>", de::toString(depth).c_str(), shader);
+
+ ProgramSources sources;
+ sources << ComputeSource(shader);
+
+ // Build and run shader
+ ShaderProgram program(m_context.getRenderContext(), sources);
+ if (program.isOk())
+ {
+ gl.useProgram(program.getProgram());
+ GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram");
+
+ // Pass output image to shader
+ gl.bindImageTexture(1, //unit
+ verifyTexture,
+ 0, //level
+ GL_TRUE, //layered
+ 0, //layer
+ GL_WRITE_ONLY, GL_R8UI);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "glBindImageTexture");
+ gl.uniform1i(1, 1 /* image_unit */);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform1i");
+
+ // Pass input sampler/image to shader
+ if (f.name != "sparseImageLoadARB")
+ {
+ gl.activeTexture(GL_TEXTURE0);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "glActiveTexture");
+ gl.bindTexture(target, texture);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture");
+ gl.uniform1i(2, 0 /* sampler_unit */);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform1i");
+ }
+ else
+ {
+ gl.bindImageTexture(1, //unit
+ texture,
+ level, //level
+ GL_FALSE, //layered
+ 0, //layer
+ GL_READ_ONLY, format);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "glBindImageTexture");
+ gl.uniform1i(1, 1 /* image_unit */);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform1i");
+ }
+
+ // Pass committed region width to shader
+ gl.uniform1i(3, widthCommitted /* committed region width */);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform1i");
+ gl.dispatchCompute(width, height, depth);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "glDispatchCompute");
+ gl.memoryBarrier(GL_ALL_BARRIER_BITS);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "glMemoryBarrier");
+
+ Texture::Bind(gl, verifyTexture, verifyTarget);
+ Texture::GetData(gl, 0, verifyTarget, GL_RED, GL_UNSIGNED_BYTE, (GLvoid*)out_data);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "Texture::GetData");
+
+ //Verify only committed region
+ for (GLint x = 0; x < width; ++x)
+ for (GLint y = 0; y < height; ++y)
+ for (GLint z = 0; z < depth; ++z)
+ {
+ GLubyte* dataRegion = exp_data + x + y * width + z * width * height;
+ GLubyte* outDataRegion = out_data + x + y * width + z * width * height;
+ if (dataRegion[0] != outDataRegion[0])
+ result = false;
+ }
+ }
+ else
+ {
+ mLog << "Compute shader compilation failed (lookup) for target: " << target << ", format: " << format
+ << ", infoLog: " << program.getShaderInfo(SHADERTYPE_COMPUTE).infoLog
+ << ", shaderSource: " << shader.c_str() << " - ";
+
+ result = false;
+ }
+ }
+
+ Texture::Delete(gl, verifyTexture);
+
+ return result;
+}
+
+/** Constructor.
+ *