1e5c31af7Sopenharmony_ci/*-------------------------------------------------------------------------
2e5c31af7Sopenharmony_ci * OpenGL Conformance Test Suite
3e5c31af7Sopenharmony_ci * -----------------------------
4e5c31af7Sopenharmony_ci *
5e5c31af7Sopenharmony_ci * Copyright (c) 2015-2016 The Khronos Group Inc.
6e5c31af7Sopenharmony_ci *
7e5c31af7Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
8e5c31af7Sopenharmony_ci * you may not use this file except in compliance with the License.
9e5c31af7Sopenharmony_ci * You may obtain a copy of the License at
10e5c31af7Sopenharmony_ci *
11e5c31af7Sopenharmony_ci *      http://www.apache.org/licenses/LICENSE-2.0
12e5c31af7Sopenharmony_ci *
13e5c31af7Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
14e5c31af7Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
15e5c31af7Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16e5c31af7Sopenharmony_ci * See the License for the specific language governing permissions and
17e5c31af7Sopenharmony_ci * limitations under the License.
18e5c31af7Sopenharmony_ci *
19e5c31af7Sopenharmony_ci */ /*!
20e5c31af7Sopenharmony_ci * \file
21e5c31af7Sopenharmony_ci * \brief
22e5c31af7Sopenharmony_ci */ /*-------------------------------------------------------------------*/
23e5c31af7Sopenharmony_ci
24e5c31af7Sopenharmony_ci/**
25e5c31af7Sopenharmony_ci */ /*!
26e5c31af7Sopenharmony_ci * \file  gl4cSparseBufferTests.cpp
27e5c31af7Sopenharmony_ci * \brief Conformance tests for the GL_ARB_sparse_buffer functionality.
28e5c31af7Sopenharmony_ci */ /*-------------------------------------------------------------------*/
29e5c31af7Sopenharmony_ci
30e5c31af7Sopenharmony_ci#include "gl4cSparseBufferTests.hpp"
31e5c31af7Sopenharmony_ci#include "gluContextInfo.hpp"
32e5c31af7Sopenharmony_ci#include "gluDefs.hpp"
33e5c31af7Sopenharmony_ci#include "glwEnums.hpp"
34e5c31af7Sopenharmony_ci#include "glwFunctions.hpp"
35e5c31af7Sopenharmony_ci#include "tcuTestLog.hpp"
36e5c31af7Sopenharmony_ci
37e5c31af7Sopenharmony_ci#include <string.h>
38e5c31af7Sopenharmony_ci#include <vector>
39e5c31af7Sopenharmony_ci
40e5c31af7Sopenharmony_ci#ifndef GL_SPARSE_BUFFER_PAGE_SIZE_ARB
41e5c31af7Sopenharmony_ci#define GL_SPARSE_BUFFER_PAGE_SIZE_ARB 0x82F8
42e5c31af7Sopenharmony_ci#endif
43e5c31af7Sopenharmony_ci#ifndef GL_SPARSE_STORAGE_BIT_ARB
44e5c31af7Sopenharmony_ci#define GL_SPARSE_STORAGE_BIT_ARB 0x0400
45e5c31af7Sopenharmony_ci#endif
46e5c31af7Sopenharmony_ci
47e5c31af7Sopenharmony_cinamespace gl4cts
48e5c31af7Sopenharmony_ci{
49e5c31af7Sopenharmony_ci/** Rounds up the provided offset so that it is aligned to the specified value (eg. page size).
50e5c31af7Sopenharmony_ci *  In other words, the result value meets the following requirements:
51e5c31af7Sopenharmony_ci *
52e5c31af7Sopenharmony_ci *  1)  result value % input value  = 0
53e5c31af7Sopenharmony_ci *  2)  result value               >= offset
54e5c31af7Sopenharmony_ci *  3) (result value - offset)     <  input value
55e5c31af7Sopenharmony_ci *
56e5c31af7Sopenharmony_ci *  @param offset Offset to be used for the rounding operation.
57e5c31af7Sopenharmony_ci *  @param value  Value to align the offset to.
58e5c31af7Sopenharmony_ci *
59e5c31af7Sopenharmony_ci *  @return Result value.
60e5c31af7Sopenharmony_ci **/
61e5c31af7Sopenharmony_ciunsigned int SparseBufferTestUtilities::alignOffset(const unsigned int& offset, const unsigned int& value)
62e5c31af7Sopenharmony_ci{
63e5c31af7Sopenharmony_ci	return offset + (value - offset % value) % value;
64e5c31af7Sopenharmony_ci}
65e5c31af7Sopenharmony_ci
66e5c31af7Sopenharmony_ci/** Builds a compute program object, using the user-specified CS code snippets.
67e5c31af7Sopenharmony_ci *
68e5c31af7Sopenharmony_ci *  @param gl                     DEQP CTS GL functions container.
69e5c31af7Sopenharmony_ci *  @param cs_body_parts          Code snippets to use for the compute shader. Must hold exactly
70e5c31af7Sopenharmony_ci *                                @param n_cs_body_parts null-terminated text strings.
71e5c31af7Sopenharmony_ci *  @param n_cs_body_parts        Number of code snippets accessible via @param cs_body_parts.
72e5c31af7Sopenharmony_ci *
73e5c31af7Sopenharmony_ci *  @return Result PO id if program has been linked successfully, 0 otherwise.
74e5c31af7Sopenharmony_ci **/
75e5c31af7Sopenharmony_ciglw::GLuint SparseBufferTestUtilities::createComputeProgram(const glw::Functions& gl, const char** cs_body_parts,
76e5c31af7Sopenharmony_ci															unsigned int n_cs_body_parts)
77e5c31af7Sopenharmony_ci{
78e5c31af7Sopenharmony_ci	glw::GLint  compile_status = GL_FALSE;
79e5c31af7Sopenharmony_ci	glw::GLuint cs_id		   = 0;
80e5c31af7Sopenharmony_ci	glw::GLint  link_status	= GL_FALSE;
81e5c31af7Sopenharmony_ci	glw::GLuint po_id		   = 0;
82e5c31af7Sopenharmony_ci	bool		result		   = true;
83e5c31af7Sopenharmony_ci
84e5c31af7Sopenharmony_ci	if (n_cs_body_parts > 0)
85e5c31af7Sopenharmony_ci	{
86e5c31af7Sopenharmony_ci		cs_id = gl.createShader(GL_COMPUTE_SHADER);
87e5c31af7Sopenharmony_ci	}
88e5c31af7Sopenharmony_ci
89e5c31af7Sopenharmony_ci	po_id = gl.createProgram();
90e5c31af7Sopenharmony_ci
91e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() / glCreateShader() call(s) failed.");
92e5c31af7Sopenharmony_ci
93e5c31af7Sopenharmony_ci	if (n_cs_body_parts > 0)
94e5c31af7Sopenharmony_ci	{
95e5c31af7Sopenharmony_ci		gl.attachShader(po_id, cs_id);
96e5c31af7Sopenharmony_ci	}
97e5c31af7Sopenharmony_ci
98e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call(s) failed.");
99e5c31af7Sopenharmony_ci
100e5c31af7Sopenharmony_ci	if (n_cs_body_parts > 0)
101e5c31af7Sopenharmony_ci	{
102e5c31af7Sopenharmony_ci		gl.shaderSource(cs_id, n_cs_body_parts, cs_body_parts, NULL); /* length */
103e5c31af7Sopenharmony_ci	}
104e5c31af7Sopenharmony_ci
105e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call(s) failed.");
106e5c31af7Sopenharmony_ci
107e5c31af7Sopenharmony_ci	gl.compileShader(cs_id);
108e5c31af7Sopenharmony_ci
109e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed.");
110e5c31af7Sopenharmony_ci
111e5c31af7Sopenharmony_ci	gl.getShaderiv(cs_id, GL_COMPILE_STATUS, &compile_status);
112e5c31af7Sopenharmony_ci
113e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed");
114e5c31af7Sopenharmony_ci
115e5c31af7Sopenharmony_ci	char temp[1024];
116e5c31af7Sopenharmony_ci	gl.getShaderInfoLog(cs_id, 1024, NULL, temp);
117e5c31af7Sopenharmony_ci
118e5c31af7Sopenharmony_ci	if (GL_TRUE != compile_status)
119e5c31af7Sopenharmony_ci	{
120e5c31af7Sopenharmony_ci		result = false;
121e5c31af7Sopenharmony_ci
122e5c31af7Sopenharmony_ci		goto end;
123e5c31af7Sopenharmony_ci	}
124e5c31af7Sopenharmony_ci
125e5c31af7Sopenharmony_ci	gl.linkProgram(po_id);
126e5c31af7Sopenharmony_ci
127e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed.");
128e5c31af7Sopenharmony_ci
129e5c31af7Sopenharmony_ci	gl.getProgramiv(po_id, GL_LINK_STATUS, &link_status);
130e5c31af7Sopenharmony_ci
131e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed.");
132e5c31af7Sopenharmony_ci
133e5c31af7Sopenharmony_ci	if (GL_TRUE != link_status)
134e5c31af7Sopenharmony_ci	{
135e5c31af7Sopenharmony_ci		result = false;
136e5c31af7Sopenharmony_ci
137e5c31af7Sopenharmony_ci		goto end;
138e5c31af7Sopenharmony_ci	}
139e5c31af7Sopenharmony_ci
140e5c31af7Sopenharmony_ciend:
141e5c31af7Sopenharmony_ci	if (cs_id != 0)
142e5c31af7Sopenharmony_ci	{
143e5c31af7Sopenharmony_ci		gl.deleteShader(cs_id);
144e5c31af7Sopenharmony_ci
145e5c31af7Sopenharmony_ci		cs_id = 0;
146e5c31af7Sopenharmony_ci	}
147e5c31af7Sopenharmony_ci
148e5c31af7Sopenharmony_ci	if (!result)
149e5c31af7Sopenharmony_ci	{
150e5c31af7Sopenharmony_ci		if (po_id != 0)
151e5c31af7Sopenharmony_ci		{
152e5c31af7Sopenharmony_ci			gl.deleteProgram(po_id);
153e5c31af7Sopenharmony_ci
154e5c31af7Sopenharmony_ci			po_id = 0;
155e5c31af7Sopenharmony_ci		}
156e5c31af7Sopenharmony_ci	} /* if (!result) */
157e5c31af7Sopenharmony_ci
158e5c31af7Sopenharmony_ci	return po_id;
159e5c31af7Sopenharmony_ci}
160e5c31af7Sopenharmony_ci
161e5c31af7Sopenharmony_ci/** Builds a program object, using the user-specified code snippets. Can optionally configure
162e5c31af7Sopenharmony_ci *  the PO to use pre-defined attribute locations & transform feed-back varyings.
163e5c31af7Sopenharmony_ci *
164e5c31af7Sopenharmony_ci *  @param gl                     DEQP CTS GL functions container.
165e5c31af7Sopenharmony_ci *  @param fs_body_parts          Code snippets to use for the fragment shader. Must hold exactly
166e5c31af7Sopenharmony_ci *                                @param n_fs_body_parts null-terminated text strings. May only
167e5c31af7Sopenharmony_ci *                                be NULL if @param n_fs_body_parts is 0.
168e5c31af7Sopenharmony_ci *  @param n_fs_body_parts        See @param fs_body_parts definitions.
169e5c31af7Sopenharmony_ci *  @param vs_body_parts          Code snippets to use for the vertex shader. Must hold exactly
170e5c31af7Sopenharmony_ci *                                @param n_vs_body_parts null-terminated text strings. May only
171e5c31af7Sopenharmony_ci *                                be NULL if @param n_vs_body_parts is 0.
172e5c31af7Sopenharmony_ci *  @param n_vs_body_parts        See @param vs_body_parts definitions.
173e5c31af7Sopenharmony_ci *  @param attribute_names        Null-terminated attribute names to pass to the
174e5c31af7Sopenharmony_ci *                                glBindAttribLocation() call.
175e5c31af7Sopenharmony_ci *                                May only be NULL if @param n_attribute_properties is 0.
176e5c31af7Sopenharmony_ci *  @param attribute_locations    Attribute locations to pass to the glBindAttribLocation() call.
177e5c31af7Sopenharmony_ci *                                May only be NULL if @param n_attribute_properties is 0.
178e5c31af7Sopenharmony_ci *  @param n_attribute_properties See @param attribute_names and @param attribute_locations definitions.
179e5c31af7Sopenharmony_ci *  @param tf_varyings            Transform-feedback varying names to use for the
180e5c31af7Sopenharmony_ci *                                glTransformFeedbackVaryings() call. May only be NULL if
181e5c31af7Sopenharmony_ci *                                @param n_tf_varyings is 0.
182e5c31af7Sopenharmony_ci *  @param n_tf_varyings          See @param tf_varyings definition.
183e5c31af7Sopenharmony_ci *  @param tf_varying_mode        Transform feedback mode to use for the
184e5c31af7Sopenharmony_ci *                                glTransformFeedbackVaryings() call. Only used if @param n_tf_varyings
185e5c31af7Sopenharmony_ci *                                is 0.
186e5c31af7Sopenharmony_ci *
187e5c31af7Sopenharmony_ci *  @return Result PO id if program has been linked successfully, 0 otherwise.
188e5c31af7Sopenharmony_ci **/
189e5c31af7Sopenharmony_ciglw::GLuint SparseBufferTestUtilities::createProgram(const glw::Functions& gl, const char** fs_body_parts,
190e5c31af7Sopenharmony_ci													 unsigned int n_fs_body_parts, const char** vs_body_parts,
191e5c31af7Sopenharmony_ci													 unsigned int n_vs_body_parts, const char** attribute_names,
192e5c31af7Sopenharmony_ci													 const unsigned int*	   attribute_locations,
193e5c31af7Sopenharmony_ci													 unsigned int			   n_attribute_properties,
194e5c31af7Sopenharmony_ci													 const glw::GLchar* const* tf_varyings, unsigned int n_tf_varyings,
195e5c31af7Sopenharmony_ci													 glw::GLenum tf_varying_mode)
196e5c31af7Sopenharmony_ci{
197e5c31af7Sopenharmony_ci	glw::GLint  compile_status = GL_FALSE;
198e5c31af7Sopenharmony_ci	glw::GLuint fs_id		   = 0;
199e5c31af7Sopenharmony_ci	glw::GLint  link_status	= GL_FALSE;
200e5c31af7Sopenharmony_ci	glw::GLuint po_id		   = 0;
201e5c31af7Sopenharmony_ci	bool		result		   = true;
202e5c31af7Sopenharmony_ci	glw::GLuint vs_id		   = 0;
203e5c31af7Sopenharmony_ci
204e5c31af7Sopenharmony_ci	if (n_fs_body_parts > 0)
205e5c31af7Sopenharmony_ci	{
206e5c31af7Sopenharmony_ci		fs_id = gl.createShader(GL_FRAGMENT_SHADER);
207e5c31af7Sopenharmony_ci	}
208e5c31af7Sopenharmony_ci
209e5c31af7Sopenharmony_ci	po_id = gl.createProgram();
210e5c31af7Sopenharmony_ci
211e5c31af7Sopenharmony_ci	if (n_vs_body_parts > 0)
212e5c31af7Sopenharmony_ci	{
213e5c31af7Sopenharmony_ci		vs_id = gl.createShader(GL_VERTEX_SHADER);
214e5c31af7Sopenharmony_ci	}
215e5c31af7Sopenharmony_ci
216e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() / glCreateShader() call(s) failed.");
217e5c31af7Sopenharmony_ci
218e5c31af7Sopenharmony_ci	if (n_fs_body_parts > 0)
219e5c31af7Sopenharmony_ci	{
220e5c31af7Sopenharmony_ci		gl.attachShader(po_id, fs_id);
221e5c31af7Sopenharmony_ci	}
222e5c31af7Sopenharmony_ci
223e5c31af7Sopenharmony_ci	if (n_vs_body_parts > 0)
224e5c31af7Sopenharmony_ci	{
225e5c31af7Sopenharmony_ci		gl.attachShader(po_id, vs_id);
226e5c31af7Sopenharmony_ci	}
227e5c31af7Sopenharmony_ci
228e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call(s) failed.");
229e5c31af7Sopenharmony_ci
230e5c31af7Sopenharmony_ci	if (n_fs_body_parts > 0)
231e5c31af7Sopenharmony_ci	{
232e5c31af7Sopenharmony_ci		gl.shaderSource(fs_id, n_fs_body_parts, fs_body_parts, NULL); /* length */
233e5c31af7Sopenharmony_ci	}
234e5c31af7Sopenharmony_ci
235e5c31af7Sopenharmony_ci	if (n_vs_body_parts > 0)
236e5c31af7Sopenharmony_ci	{
237e5c31af7Sopenharmony_ci		gl.shaderSource(vs_id, n_vs_body_parts, vs_body_parts, NULL); /* length */
238e5c31af7Sopenharmony_ci	}
239e5c31af7Sopenharmony_ci
240e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call(s) failed.");
241e5c31af7Sopenharmony_ci
242e5c31af7Sopenharmony_ci	const glw::GLuint  so_ids[] = { fs_id, vs_id };
243e5c31af7Sopenharmony_ci	const unsigned int n_so_ids = sizeof(so_ids) / sizeof(so_ids[0]);
244e5c31af7Sopenharmony_ci
245e5c31af7Sopenharmony_ci	for (unsigned int n_so_id = 0; n_so_id < n_so_ids; ++n_so_id)
246e5c31af7Sopenharmony_ci	{
247e5c31af7Sopenharmony_ci		if (so_ids[n_so_id] != 0)
248e5c31af7Sopenharmony_ci		{
249e5c31af7Sopenharmony_ci			gl.compileShader(so_ids[n_so_id]);
250e5c31af7Sopenharmony_ci
251e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed.");
252e5c31af7Sopenharmony_ci
253e5c31af7Sopenharmony_ci			gl.getShaderiv(so_ids[n_so_id], GL_COMPILE_STATUS, &compile_status);
254e5c31af7Sopenharmony_ci
255e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed");
256e5c31af7Sopenharmony_ci
257e5c31af7Sopenharmony_ci			char temp[1024];
258e5c31af7Sopenharmony_ci			gl.getShaderInfoLog(so_ids[n_so_id], 1024, NULL, temp);
259e5c31af7Sopenharmony_ci
260e5c31af7Sopenharmony_ci			if (GL_TRUE != compile_status)
261e5c31af7Sopenharmony_ci			{
262e5c31af7Sopenharmony_ci				result = false;
263e5c31af7Sopenharmony_ci
264e5c31af7Sopenharmony_ci				goto end;
265e5c31af7Sopenharmony_ci			}
266e5c31af7Sopenharmony_ci		} /* if (so_ids[n_so_id] != 0) */
267e5c31af7Sopenharmony_ci	}	 /* for (all shader object IDs) */
268e5c31af7Sopenharmony_ci
269e5c31af7Sopenharmony_ci	for (unsigned int n_attribute = 0; n_attribute < n_attribute_properties; ++n_attribute)
270e5c31af7Sopenharmony_ci	{
271e5c31af7Sopenharmony_ci		gl.bindAttribLocation(po_id, attribute_locations[n_attribute], attribute_names[n_attribute]);
272e5c31af7Sopenharmony_ci
273e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glBindAttribLocation() call failed.");
274e5c31af7Sopenharmony_ci	} /* for (all attributes to configure) */
275e5c31af7Sopenharmony_ci
276e5c31af7Sopenharmony_ci	if (n_tf_varyings != 0)
277e5c31af7Sopenharmony_ci	{
278e5c31af7Sopenharmony_ci		gl.transformFeedbackVaryings(po_id, n_tf_varyings, tf_varyings, tf_varying_mode);
279e5c31af7Sopenharmony_ci
280e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() call failed.");
281e5c31af7Sopenharmony_ci	} /* if (n_tf_varyings != 0) */
282e5c31af7Sopenharmony_ci
283e5c31af7Sopenharmony_ci	gl.linkProgram(po_id);
284e5c31af7Sopenharmony_ci
285e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed.");
286e5c31af7Sopenharmony_ci
287e5c31af7Sopenharmony_ci	gl.getProgramiv(po_id, GL_LINK_STATUS, &link_status);
288e5c31af7Sopenharmony_ci
289e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed.");
290e5c31af7Sopenharmony_ci
291e5c31af7Sopenharmony_ci	if (GL_TRUE != link_status)
292e5c31af7Sopenharmony_ci	{
293e5c31af7Sopenharmony_ci		result = false;
294e5c31af7Sopenharmony_ci
295e5c31af7Sopenharmony_ci		goto end;
296e5c31af7Sopenharmony_ci	}
297e5c31af7Sopenharmony_ci
298e5c31af7Sopenharmony_ciend:
299e5c31af7Sopenharmony_ci	if (fs_id != 0)
300e5c31af7Sopenharmony_ci	{
301e5c31af7Sopenharmony_ci		gl.deleteShader(fs_id);
302e5c31af7Sopenharmony_ci
303e5c31af7Sopenharmony_ci		fs_id = 0;
304e5c31af7Sopenharmony_ci	}
305e5c31af7Sopenharmony_ci
306e5c31af7Sopenharmony_ci	if (vs_id != 0)
307e5c31af7Sopenharmony_ci	{
308e5c31af7Sopenharmony_ci		gl.deleteShader(vs_id);
309e5c31af7Sopenharmony_ci
310e5c31af7Sopenharmony_ci		vs_id = 0;
311e5c31af7Sopenharmony_ci	}
312e5c31af7Sopenharmony_ci
313e5c31af7Sopenharmony_ci	if (!result)
314e5c31af7Sopenharmony_ci	{
315e5c31af7Sopenharmony_ci
316e5c31af7Sopenharmony_ci		if (po_id != 0)
317e5c31af7Sopenharmony_ci		{
318e5c31af7Sopenharmony_ci			gl.deleteProgram(po_id);
319e5c31af7Sopenharmony_ci
320e5c31af7Sopenharmony_ci			po_id = 0;
321e5c31af7Sopenharmony_ci		}
322e5c31af7Sopenharmony_ci	} /* if (!result) */
323e5c31af7Sopenharmony_ci
324e5c31af7Sopenharmony_ci	return po_id;
325e5c31af7Sopenharmony_ci}
326e5c31af7Sopenharmony_ci
327e5c31af7Sopenharmony_ci/** Returns a string with textual representation of the @param flags bitfield
328e5c31af7Sopenharmony_ci *  holding bits applicable to the @param flags argument of glBufferStorage()
329e5c31af7Sopenharmony_ci *  calls.
330e5c31af7Sopenharmony_ci *
331e5c31af7Sopenharmony_ci *  @param flags Flags argument, as supported by the @param flags argument of
332e5c31af7Sopenharmony_ci *               glBufferStorage() entry-point.
333e5c31af7Sopenharmony_ci *
334e5c31af7Sopenharmony_ci *  @return Described string.
335e5c31af7Sopenharmony_ci **/
336e5c31af7Sopenharmony_cistd::string SparseBufferTestUtilities::getSparseBOFlagsString(glw::GLenum flags)
337e5c31af7Sopenharmony_ci{
338e5c31af7Sopenharmony_ci	unsigned int	  n_flags_added = 0;
339e5c31af7Sopenharmony_ci	std::stringstream result_sstream;
340e5c31af7Sopenharmony_ci
341e5c31af7Sopenharmony_ci	if ((flags & GL_CLIENT_STORAGE_BIT) != 0)
342e5c31af7Sopenharmony_ci	{
343e5c31af7Sopenharmony_ci		result_sstream << "GL_CLIENT_STORAGE_BIT";
344e5c31af7Sopenharmony_ci
345e5c31af7Sopenharmony_ci		++n_flags_added;
346e5c31af7Sopenharmony_ci	}
347e5c31af7Sopenharmony_ci
348e5c31af7Sopenharmony_ci	if ((flags & GL_DYNAMIC_STORAGE_BIT) != 0)
349e5c31af7Sopenharmony_ci	{
350e5c31af7Sopenharmony_ci		result_sstream << ((n_flags_added) ? " | " : "") << "GL_DYNAMIC_STORAGE_BIT";
351e5c31af7Sopenharmony_ci
352e5c31af7Sopenharmony_ci		++n_flags_added;
353e5c31af7Sopenharmony_ci	}
354e5c31af7Sopenharmony_ci
355e5c31af7Sopenharmony_ci	if ((flags & GL_MAP_COHERENT_BIT) != 0)
356e5c31af7Sopenharmony_ci	{
357e5c31af7Sopenharmony_ci		result_sstream << ((n_flags_added) ? " | " : "") << "GL_MAP_COHERENT_BIT";
358e5c31af7Sopenharmony_ci
359e5c31af7Sopenharmony_ci		++n_flags_added;
360e5c31af7Sopenharmony_ci	}
361e5c31af7Sopenharmony_ci
362e5c31af7Sopenharmony_ci	if ((flags & GL_MAP_PERSISTENT_BIT) != 0)
363e5c31af7Sopenharmony_ci	{
364e5c31af7Sopenharmony_ci		result_sstream << ((n_flags_added) ? " | " : "") << "GL_MAP_PERSISTENT_BIT";
365e5c31af7Sopenharmony_ci
366e5c31af7Sopenharmony_ci		++n_flags_added;
367e5c31af7Sopenharmony_ci	}
368e5c31af7Sopenharmony_ci
369e5c31af7Sopenharmony_ci	if ((flags & GL_SPARSE_STORAGE_BIT_ARB) != 0)
370e5c31af7Sopenharmony_ci	{
371e5c31af7Sopenharmony_ci		result_sstream << ((n_flags_added) ? " | " : "") << "GL_SPARSE_STORAGE_BIT";
372e5c31af7Sopenharmony_ci
373e5c31af7Sopenharmony_ci		++n_flags_added;
374e5c31af7Sopenharmony_ci	}
375e5c31af7Sopenharmony_ci
376e5c31af7Sopenharmony_ci	return result_sstream.str();
377e5c31af7Sopenharmony_ci}
378e5c31af7Sopenharmony_ci
379e5c31af7Sopenharmony_ci/** Constructor.
380e5c31af7Sopenharmony_ci *
381e5c31af7Sopenharmony_ci *  @param context     Rendering context
382e5c31af7Sopenharmony_ci *  @param name        Test name
383e5c31af7Sopenharmony_ci *  @param description Test description
384e5c31af7Sopenharmony_ci */
385e5c31af7Sopenharmony_ciNegativeTests::NegativeTests(deqp::Context& context)
386e5c31af7Sopenharmony_ci	: TestCase(context, "NegativeTests", "Implements all negative tests described in CTS_ARB_sparse_buffer")
387e5c31af7Sopenharmony_ci	, m_helper_bo_id(0)
388e5c31af7Sopenharmony_ci	, m_immutable_bo_id(0)
389e5c31af7Sopenharmony_ci	, m_immutable_bo_size(1024768)
390e5c31af7Sopenharmony_ci	, m_sparse_bo_id(0)
391e5c31af7Sopenharmony_ci{
392e5c31af7Sopenharmony_ci	/* Left blank intentionally */
393e5c31af7Sopenharmony_ci}
394e5c31af7Sopenharmony_ci
395e5c31af7Sopenharmony_ci/** Stub deinit method. */
396e5c31af7Sopenharmony_civoid NegativeTests::deinit()
397e5c31af7Sopenharmony_ci{
398e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
399e5c31af7Sopenharmony_ci
400e5c31af7Sopenharmony_ci	if (m_helper_bo_id != 0)
401e5c31af7Sopenharmony_ci	{
402e5c31af7Sopenharmony_ci		gl.deleteBuffers(1, &m_helper_bo_id);
403e5c31af7Sopenharmony_ci
404e5c31af7Sopenharmony_ci		m_helper_bo_id = 0;
405e5c31af7Sopenharmony_ci	}
406e5c31af7Sopenharmony_ci
407e5c31af7Sopenharmony_ci	if (m_immutable_bo_id != 0)
408e5c31af7Sopenharmony_ci	{
409e5c31af7Sopenharmony_ci		gl.deleteBuffers(1, &m_immutable_bo_id);
410e5c31af7Sopenharmony_ci
411e5c31af7Sopenharmony_ci		m_immutable_bo_id = 0;
412e5c31af7Sopenharmony_ci	}
413e5c31af7Sopenharmony_ci
414e5c31af7Sopenharmony_ci	if (m_sparse_bo_id != 0)
415e5c31af7Sopenharmony_ci	{
416e5c31af7Sopenharmony_ci		gl.deleteBuffers(1, &m_sparse_bo_id);
417e5c31af7Sopenharmony_ci
418e5c31af7Sopenharmony_ci		m_sparse_bo_id = 0;
419e5c31af7Sopenharmony_ci	}
420e5c31af7Sopenharmony_ci}
421e5c31af7Sopenharmony_ci
422e5c31af7Sopenharmony_ci/** Stub init method */
423e5c31af7Sopenharmony_civoid NegativeTests::init()
424e5c31af7Sopenharmony_ci{
425e5c31af7Sopenharmony_ci	/* Nothing to do here */
426e5c31af7Sopenharmony_ci}
427e5c31af7Sopenharmony_ci
428e5c31af7Sopenharmony_ci/** Executes test iteration.
429e5c31af7Sopenharmony_ci *
430e5c31af7Sopenharmony_ci *  @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
431e5c31af7Sopenharmony_ci */
432e5c31af7Sopenharmony_citcu::TestNode::IterateResult NegativeTests::iterate()
433e5c31af7Sopenharmony_ci{
434e5c31af7Sopenharmony_ci	glw::GLvoid*		  data_ptr  = DE_NULL;
435e5c31af7Sopenharmony_ci	const glw::Functions& gl		= m_context.getRenderContext().getFunctions();
436e5c31af7Sopenharmony_ci	glw::GLint			  page_size = 0;
437e5c31af7Sopenharmony_ci	bool				  result	= true;
438e5c31af7Sopenharmony_ci
439e5c31af7Sopenharmony_ci	/* Only execute if the implementation supports the GL_ARB_sparse_buffer extension */
440e5c31af7Sopenharmony_ci	if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_sparse_buffer"))
441e5c31af7Sopenharmony_ci	{
442e5c31af7Sopenharmony_ci		throw tcu::NotSupportedError("GL_ARB_sparse_buffer is not supported");
443e5c31af7Sopenharmony_ci	}
444e5c31af7Sopenharmony_ci
445e5c31af7Sopenharmony_ci	/* Set up */
446e5c31af7Sopenharmony_ci	gl.getIntegerv(GL_SPARSE_BUFFER_PAGE_SIZE_ARB, &page_size);
447e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() call failed.");
448e5c31af7Sopenharmony_ci
449e5c31af7Sopenharmony_ci	gl.genBuffers(1, &m_helper_bo_id);
450e5c31af7Sopenharmony_ci	gl.genBuffers(1, &m_immutable_bo_id);
451e5c31af7Sopenharmony_ci	gl.genBuffers(1, &m_sparse_bo_id);
452e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call(s) failed.");
453e5c31af7Sopenharmony_ci
454e5c31af7Sopenharmony_ci	gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo_id);
455e5c31af7Sopenharmony_ci	gl.bindBuffer(GL_COPY_READ_BUFFER, m_immutable_bo_id);
456e5c31af7Sopenharmony_ci	gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_helper_bo_id);
457e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed.");
458e5c31af7Sopenharmony_ci
459e5c31af7Sopenharmony_ci	gl.bufferStorage(GL_ARRAY_BUFFER, page_size * 3, /* size as per test spec */
460e5c31af7Sopenharmony_ci					 DE_NULL,						 /* data */
461e5c31af7Sopenharmony_ci					 GL_SPARSE_STORAGE_BIT_ARB);
462e5c31af7Sopenharmony_ci	gl.bufferStorage(GL_COPY_READ_BUFFER, m_immutable_bo_size, /* size */
463e5c31af7Sopenharmony_ci					 DE_NULL,								   /* data */
464e5c31af7Sopenharmony_ci					 0);
465e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferStorage() call(s) failed.");
466e5c31af7Sopenharmony_ci
467e5c31af7Sopenharmony_ci	/** * Verify glBufferPageCommitmentARB() returns GL_INVALID_ENUM if <target> is
468e5c31af7Sopenharmony_ci	 *    set to GL_INTERLEAVED_ATTRIBS. */
469e5c31af7Sopenharmony_ci	glw::GLint error_code = GL_NO_ERROR;
470e5c31af7Sopenharmony_ci
471e5c31af7Sopenharmony_ci	gl.bufferPageCommitmentARB(GL_INTERLEAVED_ATTRIBS, 0, /* offset */
472e5c31af7Sopenharmony_ci							   page_size, GL_TRUE);		  /* commit */
473e5c31af7Sopenharmony_ci
474e5c31af7Sopenharmony_ci	error_code = gl.getError();
475e5c31af7Sopenharmony_ci	if (error_code != GL_INVALID_ENUM)
476e5c31af7Sopenharmony_ci	{
477e5c31af7Sopenharmony_ci		m_testCtx.getLog() << tcu::TestLog::Message
478e5c31af7Sopenharmony_ci						   << "Invalid <target> value passed to a glBufferPageCommitmentARB() call"
479e5c31af7Sopenharmony_ci							  " did not generate a GL_INVALID_ENUM error."
480e5c31af7Sopenharmony_ci						   << tcu::TestLog::EndMessage;
481e5c31af7Sopenharmony_ci
482e5c31af7Sopenharmony_ci		result = false;
483e5c31af7Sopenharmony_ci	}
484e5c31af7Sopenharmony_ci
485e5c31af7Sopenharmony_ci	/*  * Verify glBufferStorage() throws a GL_INVALID_VALUE error if <flags> is
486e5c31af7Sopenharmony_ci	 *    set to (GL_SPARSE_STORAGE_BIT_ARB | GL_MAP_READ_BIT) or
487e5c31af7Sopenharmony_ci	 *    (GL_SPARSE_STORAGE_BIT_ARB | GL_MAP_WRITE_BIT). */
488e5c31af7Sopenharmony_ci	gl.bufferStorage(GL_ELEMENT_ARRAY_BUFFER, page_size * 3, /* size */
489e5c31af7Sopenharmony_ci					 DE_NULL,								 /* data */
490e5c31af7Sopenharmony_ci					 GL_SPARSE_STORAGE_BIT_ARB | GL_MAP_READ_BIT);
491e5c31af7Sopenharmony_ci
492e5c31af7Sopenharmony_ci	error_code = gl.getError();
493e5c31af7Sopenharmony_ci	if (error_code != GL_INVALID_VALUE)
494e5c31af7Sopenharmony_ci	{
495e5c31af7Sopenharmony_ci		m_testCtx.getLog() << tcu::TestLog::Message
496e5c31af7Sopenharmony_ci						   << "Invalid <flags> value set to GL_SPARSE_STORAGE_BIT_ARB | GL_MAP_READ_BIT "
497e5c31af7Sopenharmony_ci							  "did not generate a GL_INVALID_VALUE error."
498e5c31af7Sopenharmony_ci						   << tcu::TestLog::EndMessage;
499e5c31af7Sopenharmony_ci
500e5c31af7Sopenharmony_ci		result = false;
501e5c31af7Sopenharmony_ci	}
502e5c31af7Sopenharmony_ci
503e5c31af7Sopenharmony_ci	gl.bufferStorage(GL_ELEMENT_ARRAY_BUFFER, page_size * 3, /* size */
504e5c31af7Sopenharmony_ci					 DE_NULL,								 /* data */
505e5c31af7Sopenharmony_ci					 GL_SPARSE_STORAGE_BIT_ARB | GL_MAP_WRITE_BIT);
506e5c31af7Sopenharmony_ci
507e5c31af7Sopenharmony_ci	error_code = gl.getError();
508e5c31af7Sopenharmony_ci	if (error_code != GL_INVALID_VALUE)
509e5c31af7Sopenharmony_ci	{
510e5c31af7Sopenharmony_ci		m_testCtx.getLog() << tcu::TestLog::Message
511e5c31af7Sopenharmony_ci						   << "Invalid <flags> value set to GL_SPARSE_STORAGE_BIT_ARB | GL_MAP_WRITE_BIT "
512e5c31af7Sopenharmony_ci							  "did not generate a GL_INVALID_VALUE error."
513e5c31af7Sopenharmony_ci						   << tcu::TestLog::EndMessage;
514e5c31af7Sopenharmony_ci
515e5c31af7Sopenharmony_ci		result = false;
516e5c31af7Sopenharmony_ci	}
517e5c31af7Sopenharmony_ci
518e5c31af7Sopenharmony_ci	/*  * Verify glBufferPageCommitmentARB() generates a GL_INVALID_OPERATION error if
519e5c31af7Sopenharmony_ci	 *    it is called for an immutable BO, which has not been initialized with the
520e5c31af7Sopenharmony_ci	 *    GL_SPARSE_STORAGE_BIT_ARB flag. */
521e5c31af7Sopenharmony_ci	gl.bufferPageCommitmentARB(GL_COPY_READ_BUFFER, 0, /* offset */
522e5c31af7Sopenharmony_ci							   page_size, GL_TRUE);	/* commit */
523e5c31af7Sopenharmony_ci
524e5c31af7Sopenharmony_ci	error_code = gl.getError();
525e5c31af7Sopenharmony_ci	if (error_code != GL_INVALID_OPERATION)
526e5c31af7Sopenharmony_ci	{
527e5c31af7Sopenharmony_ci		m_testCtx.getLog() << tcu::TestLog::Message << "Invalid error code generated by glBufferPageCommitmentARB() "
528e5c31af7Sopenharmony_ci													   " issued against an immutable, non-sparse buffer object."
529e5c31af7Sopenharmony_ci						   << tcu::TestLog::EndMessage;
530e5c31af7Sopenharmony_ci
531e5c31af7Sopenharmony_ci		result = false;
532e5c31af7Sopenharmony_ci	}
533e5c31af7Sopenharmony_ci
534e5c31af7Sopenharmony_ci	/*  * Verify glBufferPageCommitmentARB() issues a GL_INVALID_VALUE error if <offset>
535e5c31af7Sopenharmony_ci	 *    is set to (0.5 * GL_SPARSE_BUFFER_PAGE_SIZE_ARB). Skip if the constant's value
536e5c31af7Sopenharmony_ci	 *    is equal to 1. */
537e5c31af7Sopenharmony_ci	if (page_size != 1)
538e5c31af7Sopenharmony_ci	{
539e5c31af7Sopenharmony_ci		gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, page_size / 2, /* offset */
540e5c31af7Sopenharmony_ci								   page_size, GL_TRUE);			   /* commit */
541e5c31af7Sopenharmony_ci
542e5c31af7Sopenharmony_ci		error_code = gl.getError();
543e5c31af7Sopenharmony_ci		if (error_code != GL_INVALID_VALUE)
544e5c31af7Sopenharmony_ci		{
545e5c31af7Sopenharmony_ci			m_testCtx.getLog() << tcu::TestLog::Message
546e5c31af7Sopenharmony_ci							   << "Invalid error code generated by glBufferPageCommitmentARB() "
547e5c31af7Sopenharmony_ci								  "whose <offset> value was set to (page size / 2)."
548e5c31af7Sopenharmony_ci							   << tcu::TestLog::EndMessage;
549e5c31af7Sopenharmony_ci
550e5c31af7Sopenharmony_ci			result = false;
551e5c31af7Sopenharmony_ci		}
552e5c31af7Sopenharmony_ci	} /* if (page_size != 1) */
553e5c31af7Sopenharmony_ci
554e5c31af7Sopenharmony_ci	/*  * Verify glBufferPageCommitmentARB() emits a GL_INVALID_VALUE error if <size>
555e5c31af7Sopenharmony_ci	 *    is set to (0.5 * GL_SPARSE_BUFFER_PAGE_SIZE_ARB). Skip if the constant's value
556e5c31af7Sopenharmony_ci	 *    is equal to 1. */
557e5c31af7Sopenharmony_ci	if (page_size != 1)
558e5c31af7Sopenharmony_ci	{
559e5c31af7Sopenharmony_ci		gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,		/* offset */
560e5c31af7Sopenharmony_ci								   page_size / 2, GL_TRUE); /* commit */
561e5c31af7Sopenharmony_ci
562e5c31af7Sopenharmony_ci		error_code = gl.getError();
563e5c31af7Sopenharmony_ci		if (error_code != GL_INVALID_VALUE)
564e5c31af7Sopenharmony_ci		{
565e5c31af7Sopenharmony_ci			m_testCtx.getLog() << tcu::TestLog::Message
566e5c31af7Sopenharmony_ci							   << "Invalid error code generated by glBufferPageCommitmentARB() "
567e5c31af7Sopenharmony_ci								  "whose <size> value was set to (page size / 2)."
568e5c31af7Sopenharmony_ci							   << tcu::TestLog::EndMessage;
569e5c31af7Sopenharmony_ci
570e5c31af7Sopenharmony_ci			result = false;
571e5c31af7Sopenharmony_ci		}
572e5c31af7Sopenharmony_ci	} /* if (page_size != 1) */
573e5c31af7Sopenharmony_ci
574e5c31af7Sopenharmony_ci	/*  * Verify glBufferPageCommitmentARB() returns GL_INVALID_VALUE if <offset> is
575e5c31af7Sopenharmony_ci	 *    set to -1, but all other arguments are valid. */
576e5c31af7Sopenharmony_ci	gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, -1, /* offset */
577e5c31af7Sopenharmony_ci							   page_size, GL_TRUE); /* commit */
578e5c31af7Sopenharmony_ci
579e5c31af7Sopenharmony_ci	error_code = gl.getError();
580e5c31af7Sopenharmony_ci	if (error_code != GL_INVALID_VALUE)
581e5c31af7Sopenharmony_ci	{
582e5c31af7Sopenharmony_ci		m_testCtx.getLog() << tcu::TestLog::Message << "Invalid error code generated by glBufferPageCommitmentARB() "
583e5c31af7Sopenharmony_ci													   "whose <offset> argument was set to -1."
584e5c31af7Sopenharmony_ci						   << tcu::TestLog::EndMessage;
585e5c31af7Sopenharmony_ci
586e5c31af7Sopenharmony_ci		result = false;
587e5c31af7Sopenharmony_ci	}
588e5c31af7Sopenharmony_ci
589e5c31af7Sopenharmony_ci	/*  * Verify glBufferPageCommitmentARB() returns GL_INVALID_VALUE if <size> is
590e5c31af7Sopenharmony_ci	 *    set to -1, but all other arguments are valid. */
591e5c31af7Sopenharmony_ci	gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0, /* offset */
592e5c31af7Sopenharmony_ci							   -1,				   /* size */
593e5c31af7Sopenharmony_ci							   GL_TRUE);		   /* commit */
594e5c31af7Sopenharmony_ci
595e5c31af7Sopenharmony_ci	error_code = gl.getError();
596e5c31af7Sopenharmony_ci	if (error_code != GL_INVALID_VALUE)
597e5c31af7Sopenharmony_ci	{
598e5c31af7Sopenharmony_ci		m_testCtx.getLog() << tcu::TestLog::Message << "Invalid error code generated by glBufferPageCommitmentARB() "
599e5c31af7Sopenharmony_ci													   "whose <size> argument was set to -1."
600e5c31af7Sopenharmony_ci						   << tcu::TestLog::EndMessage;
601e5c31af7Sopenharmony_ci
602e5c31af7Sopenharmony_ci		result = false;
603e5c31af7Sopenharmony_ci	}
604e5c31af7Sopenharmony_ci
605e5c31af7Sopenharmony_ci	/*  * Verify glBufferPageCommitmentARB() returns GL_INVALID_VALUE if BO's size is
606e5c31af7Sopenharmony_ci	 *    GL_SPARSE_BUFFER_PAGE_SIZE_ARB * 3, but the <offset> is set to 0 and <size>
607e5c31af7Sopenharmony_ci	 *    argument used for the call is set to GL_SPARSE_BUFFER_PAGE_SIZE_ARB * 4. */
608e5c31af7Sopenharmony_ci	gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0, /* offset */
609e5c31af7Sopenharmony_ci							   page_size * 4,	  /* size */
610e5c31af7Sopenharmony_ci							   GL_TRUE);
611e5c31af7Sopenharmony_ci
612e5c31af7Sopenharmony_ci	error_code = gl.getError();
613e5c31af7Sopenharmony_ci	if (error_code != GL_INVALID_VALUE)
614e5c31af7Sopenharmony_ci	{
615e5c31af7Sopenharmony_ci		m_testCtx.getLog() << tcu::TestLog::Message
616e5c31af7Sopenharmony_ci						   << "Invalid error code generated by glBufferPageCommitmentARB() "
617e5c31af7Sopenharmony_ci							  "whose <offset> was set to 0 and <size> was set to (page size * 4), "
618e5c31af7Sopenharmony_ci							  "when the buffer storage size had been configured to be (page size * 3)."
619e5c31af7Sopenharmony_ci						   << tcu::TestLog::EndMessage;
620e5c31af7Sopenharmony_ci
621e5c31af7Sopenharmony_ci		result = false;
622e5c31af7Sopenharmony_ci	}
623e5c31af7Sopenharmony_ci
624e5c31af7Sopenharmony_ci	/*  * Verify glBufferPageCommitmentARB() returns GL_INVALID_VALUE if BO's size is
625e5c31af7Sopenharmony_ci	 *    GL_SPARSE_BUFFER_PAGE_SIZE_ARB * 3, but the <offset> is set to
626e5c31af7Sopenharmony_ci	 *    GL_SPARSE_BUFFER_PAGE_SIZE_ARB * 1 and <size> argument used for the call
627e5c31af7Sopenharmony_ci	 *    is set to GL_SPARSE_BUFFER_PAGE_SIZE_ARB * 3. */
628e5c31af7Sopenharmony_ci	gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, page_size * 1, /* offset */
629e5c31af7Sopenharmony_ci							   page_size * 3,				   /* size */
630e5c31af7Sopenharmony_ci							   GL_TRUE);
631e5c31af7Sopenharmony_ci
632e5c31af7Sopenharmony_ci	error_code = gl.getError();
633e5c31af7Sopenharmony_ci	if (error_code != GL_INVALID_VALUE)
634e5c31af7Sopenharmony_ci	{
635e5c31af7Sopenharmony_ci		m_testCtx.getLog() << tcu::TestLog::Message
636e5c31af7Sopenharmony_ci						   << "Invalid error code generated by glBufferPageCommitmentARB() "
637e5c31af7Sopenharmony_ci							  "whose <offset> was set to (page size) and <size> was set to (page size * 3), "
638e5c31af7Sopenharmony_ci							  "when the buffer storage size had been configured to be (page size * 3)."
639e5c31af7Sopenharmony_ci						   << tcu::TestLog::EndMessage;
640e5c31af7Sopenharmony_ci
641e5c31af7Sopenharmony_ci		result = false;
642e5c31af7Sopenharmony_ci	}
643e5c31af7Sopenharmony_ci
644e5c31af7Sopenharmony_ci	/*  * Verify that calling glMapBuffer() or glMapBufferRange() against a sparse
645e5c31af7Sopenharmony_ci	 *    buffer generates a GL_INVALID_OPERATION error. */
646e5c31af7Sopenharmony_ci	data_ptr = gl.mapBuffer(GL_ARRAY_BUFFER, GL_READ_ONLY);
647e5c31af7Sopenharmony_ci
648e5c31af7Sopenharmony_ci	if (data_ptr != DE_NULL)
649e5c31af7Sopenharmony_ci	{
650e5c31af7Sopenharmony_ci		m_testCtx.getLog() << tcu::TestLog::Message
651e5c31af7Sopenharmony_ci						   << "Non-NULL pointer returned by an invalid glMapBuffer() call, issued "
652e5c31af7Sopenharmony_ci							  "against a sparse buffer object"
653e5c31af7Sopenharmony_ci						   << tcu::TestLog::EndMessage;
654e5c31af7Sopenharmony_ci
655e5c31af7Sopenharmony_ci		result = false;
656e5c31af7Sopenharmony_ci	}
657e5c31af7Sopenharmony_ci
658e5c31af7Sopenharmony_ci	error_code = gl.getError();
659e5c31af7Sopenharmony_ci
660e5c31af7Sopenharmony_ci	if (error_code != GL_INVALID_OPERATION)
661e5c31af7Sopenharmony_ci	{
662e5c31af7Sopenharmony_ci		m_testCtx.getLog() << tcu::TestLog::Message
663e5c31af7Sopenharmony_ci						   << "Invalid error code generated by glMapBuffer() call, issued against "
664e5c31af7Sopenharmony_ci							  "a sparse buffer object"
665e5c31af7Sopenharmony_ci						   << tcu::TestLog::EndMessage;
666e5c31af7Sopenharmony_ci
667e5c31af7Sopenharmony_ci		result = false;
668e5c31af7Sopenharmony_ci	}
669e5c31af7Sopenharmony_ci
670e5c31af7Sopenharmony_ci	data_ptr = gl.mapBufferRange(GL_ARRAY_BUFFER, 0, /* offset */
671e5c31af7Sopenharmony_ci								 page_size,			 /* length */
672e5c31af7Sopenharmony_ci								 GL_MAP_READ_BIT);
673e5c31af7Sopenharmony_ci
674e5c31af7Sopenharmony_ci	if (data_ptr != DE_NULL)
675e5c31af7Sopenharmony_ci	{
676e5c31af7Sopenharmony_ci		m_testCtx.getLog() << tcu::TestLog::Message
677e5c31af7Sopenharmony_ci						   << "Non-NULL pointer returned by an invalid glMapBufferRange() call, issued "
678e5c31af7Sopenharmony_ci							  "against a sparse buffer object"
679e5c31af7Sopenharmony_ci						   << tcu::TestLog::EndMessage;
680e5c31af7Sopenharmony_ci
681e5c31af7Sopenharmony_ci		result = false;
682e5c31af7Sopenharmony_ci	}
683e5c31af7Sopenharmony_ci
684e5c31af7Sopenharmony_ci	error_code = gl.getError();
685e5c31af7Sopenharmony_ci
686e5c31af7Sopenharmony_ci	if (error_code != GL_INVALID_OPERATION)
687e5c31af7Sopenharmony_ci	{
688e5c31af7Sopenharmony_ci		m_testCtx.getLog() << tcu::TestLog::Message
689e5c31af7Sopenharmony_ci						   << "Invalid error code generated by glMapBufferRange() call, issued against "
690e5c31af7Sopenharmony_ci							  "a sparse buffer object"
691e5c31af7Sopenharmony_ci						   << tcu::TestLog::EndMessage;
692e5c31af7Sopenharmony_ci
693e5c31af7Sopenharmony_ci		result = false;
694e5c31af7Sopenharmony_ci	}
695e5c31af7Sopenharmony_ci
696e5c31af7Sopenharmony_ci	m_testCtx.setTestResult(result ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, result ? "Pass" : "Fail");
697e5c31af7Sopenharmony_ci
698e5c31af7Sopenharmony_ci	return STOP;
699e5c31af7Sopenharmony_ci}
700e5c31af7Sopenharmony_ci
701e5c31af7Sopenharmony_ci/** Constructor.
702e5c31af7Sopenharmony_ci *
703e5c31af7Sopenharmony_ci *  @param context     Rendering context
704e5c31af7Sopenharmony_ci *  @param name        Test name
705e5c31af7Sopenharmony_ci *  @param description Test description
706e5c31af7Sopenharmony_ci */
707e5c31af7Sopenharmony_ciPageSizeGetterTest::PageSizeGetterTest(deqp::Context& context)
708e5c31af7Sopenharmony_ci	: TestCase(context, "PageSizeGetterTest",
709e5c31af7Sopenharmony_ci			   "Verifies GL_SPARSE_BUFFER_PAGE_SIZE_ARB pname is recognized by the getter functions")
710e5c31af7Sopenharmony_ci{
711e5c31af7Sopenharmony_ci	/* Left blank intentionally */
712e5c31af7Sopenharmony_ci}
713e5c31af7Sopenharmony_ci
714e5c31af7Sopenharmony_ci/** Stub deinit method. */
715e5c31af7Sopenharmony_civoid PageSizeGetterTest::deinit()
716e5c31af7Sopenharmony_ci{
717e5c31af7Sopenharmony_ci	/* Nothing to be done here */
718e5c31af7Sopenharmony_ci}
719e5c31af7Sopenharmony_ci
720e5c31af7Sopenharmony_ci/** Stub init method */
721e5c31af7Sopenharmony_civoid PageSizeGetterTest::init()
722e5c31af7Sopenharmony_ci{
723e5c31af7Sopenharmony_ci	/* Nothing to do here */
724e5c31af7Sopenharmony_ci}
725e5c31af7Sopenharmony_ci
726e5c31af7Sopenharmony_ci/** Executes test iteration.
727e5c31af7Sopenharmony_ci *
728e5c31af7Sopenharmony_ci *  @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
729e5c31af7Sopenharmony_ci */
730e5c31af7Sopenharmony_citcu::TestNode::IterateResult PageSizeGetterTest::iterate()
731e5c31af7Sopenharmony_ci{
732e5c31af7Sopenharmony_ci	const glw::Functions& gl			   = m_context.getRenderContext().getFunctions();
733e5c31af7Sopenharmony_ci	glw::GLboolean		  page_size_bool   = false;
734e5c31af7Sopenharmony_ci	glw::GLdouble		  page_size_double = 0.0;
735e5c31af7Sopenharmony_ci	glw::GLfloat		  page_size_float  = 0.0f;
736e5c31af7Sopenharmony_ci	glw::GLint			  page_size_int	= 0;
737e5c31af7Sopenharmony_ci	glw::GLint64		  page_size_int64  = 0;
738e5c31af7Sopenharmony_ci	bool				  result		   = true;
739e5c31af7Sopenharmony_ci
740e5c31af7Sopenharmony_ci	/* Only execute if the implementation supports the GL_ARB_sparse_buffer extension */
741e5c31af7Sopenharmony_ci	if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_sparse_buffer"))
742e5c31af7Sopenharmony_ci	{
743e5c31af7Sopenharmony_ci		throw tcu::NotSupportedError("GL_ARB_sparse_buffer is not supported");
744e5c31af7Sopenharmony_ci	}
745e5c31af7Sopenharmony_ci
746e5c31af7Sopenharmony_ci	/* glGetIntegerv() */
747e5c31af7Sopenharmony_ci	gl.getIntegerv(GL_SPARSE_BUFFER_PAGE_SIZE_ARB, &page_size_int);
748e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() call failed");
749e5c31af7Sopenharmony_ci
750e5c31af7Sopenharmony_ci	if (page_size_int < 1 || page_size_int > 65536)
751e5c31af7Sopenharmony_ci	{
752e5c31af7Sopenharmony_ci		m_testCtx.getLog() << tcu::TestLog::Message << "Page size reported by the implementation (" << page_size_int
753e5c31af7Sopenharmony_ci						   << ")"
754e5c31af7Sopenharmony_ci							  " by glGetIntegerv() is out of the allowed range."
755e5c31af7Sopenharmony_ci						   << tcu::TestLog::EndMessage;
756e5c31af7Sopenharmony_ci
757e5c31af7Sopenharmony_ci		result = false;
758e5c31af7Sopenharmony_ci	}
759e5c31af7Sopenharmony_ci
760e5c31af7Sopenharmony_ci	/* glGetBooleanv() */
761e5c31af7Sopenharmony_ci	gl.getBooleanv(GL_SPARSE_BUFFER_PAGE_SIZE_ARB, &page_size_bool);
762e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetBooleanv() call failed");
763e5c31af7Sopenharmony_ci
764e5c31af7Sopenharmony_ci	if (!page_size_bool)
765e5c31af7Sopenharmony_ci	{
766e5c31af7Sopenharmony_ci		m_testCtx.getLog() << tcu::TestLog::Message << "Invalid page size reported by glGetBooleanv()"
767e5c31af7Sopenharmony_ci						   << tcu::TestLog::EndMessage;
768e5c31af7Sopenharmony_ci
769e5c31af7Sopenharmony_ci		result = false;
770e5c31af7Sopenharmony_ci	}
771e5c31af7Sopenharmony_ci
772e5c31af7Sopenharmony_ci	/* glGetDoublev() */
773e5c31af7Sopenharmony_ci	gl.getDoublev(GL_SPARSE_BUFFER_PAGE_SIZE_ARB, &page_size_double);
774e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetDoublev() call failed");
775e5c31af7Sopenharmony_ci
776e5c31af7Sopenharmony_ci	if (de::abs(page_size_double - page_size_int) > 1e-5)
777e5c31af7Sopenharmony_ci	{
778e5c31af7Sopenharmony_ci		m_testCtx.getLog() << tcu::TestLog::Message << "Invalid page size reported by glGetDoublev()"
779e5c31af7Sopenharmony_ci													   " (reported value: "
780e5c31af7Sopenharmony_ci						   << page_size_double << ", expected value: " << page_size_int << ")"
781e5c31af7Sopenharmony_ci						   << tcu::TestLog::EndMessage;
782e5c31af7Sopenharmony_ci
783e5c31af7Sopenharmony_ci		result = false;
784e5c31af7Sopenharmony_ci	}
785e5c31af7Sopenharmony_ci
786e5c31af7Sopenharmony_ci	/* glGetFloatv() */
787e5c31af7Sopenharmony_ci	gl.getFloatv(GL_SPARSE_BUFFER_PAGE_SIZE_ARB, &page_size_float);
788e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetFloatv() call failed");
789e5c31af7Sopenharmony_ci
790e5c31af7Sopenharmony_ci	if (de::abs(page_size_float - static_cast<float>(page_size_int)) > 1e-5f)
791e5c31af7Sopenharmony_ci	{
792e5c31af7Sopenharmony_ci		m_testCtx.getLog() << tcu::TestLog::Message << "Invalid page size reported by glGetFloatv()"
793e5c31af7Sopenharmony_ci													   " (reported value: "
794e5c31af7Sopenharmony_ci						   << page_size_float << ", expected value: " << page_size_int << ")"
795e5c31af7Sopenharmony_ci						   << tcu::TestLog::EndMessage;
796e5c31af7Sopenharmony_ci
797e5c31af7Sopenharmony_ci		result = false;
798e5c31af7Sopenharmony_ci	}
799e5c31af7Sopenharmony_ci
800e5c31af7Sopenharmony_ci	/* glGetInteger64v() */
801e5c31af7Sopenharmony_ci	gl.getInteger64v(GL_SPARSE_BUFFER_PAGE_SIZE_ARB, &page_size_int64);
802e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetFloatv() call failed");
803e5c31af7Sopenharmony_ci
804e5c31af7Sopenharmony_ci	if (page_size_int64 != page_size_int)
805e5c31af7Sopenharmony_ci	{
806e5c31af7Sopenharmony_ci		m_testCtx.getLog() << tcu::TestLog::Message << "Invalid page size reported by glGetInteger64v()"
807e5c31af7Sopenharmony_ci													   " (reported value: "
808e5c31af7Sopenharmony_ci						   << page_size_int64 << ", expected value: " << page_size_int << ")"
809e5c31af7Sopenharmony_ci						   << tcu::TestLog::EndMessage;
810e5c31af7Sopenharmony_ci
811e5c31af7Sopenharmony_ci		result = false;
812e5c31af7Sopenharmony_ci	}
813e5c31af7Sopenharmony_ci
814e5c31af7Sopenharmony_ci	m_testCtx.setTestResult(result ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, result ? "Pass" : "Fail");
815e5c31af7Sopenharmony_ci
816e5c31af7Sopenharmony_ci	return STOP;
817e5c31af7Sopenharmony_ci}
818e5c31af7Sopenharmony_ci
819e5c31af7Sopenharmony_ci/** Constructor.
820e5c31af7Sopenharmony_ci *
821e5c31af7Sopenharmony_ci *  @param gl                         GL entry-points container
822e5c31af7Sopenharmony_ci *  @param testContext                CTS test context
823e5c31af7Sopenharmony_ci *  @param page_size                  Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query.
824e5c31af7Sopenharmony_ci *  @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point.
825e5c31af7Sopenharmony_ci *  @param all_pages_committed        true to run the test with all data memory pages committed,
826e5c31af7Sopenharmony_ci *                                    false to leave some of them without an actual memory backing.
827e5c31af7Sopenharmony_ci */
828e5c31af7Sopenharmony_ciAtomicCounterBufferStorageTestCase::AtomicCounterBufferStorageTestCase(const glw::Functions& gl,
829e5c31af7Sopenharmony_ci																	   tcu::TestContext&	 testContext,
830e5c31af7Sopenharmony_ci																	   glw::GLint page_size, bool all_pages_committed)
831e5c31af7Sopenharmony_ci	: m_all_pages_committed(all_pages_committed)
832e5c31af7Sopenharmony_ci	, m_gl(gl)
833e5c31af7Sopenharmony_ci	, m_gl_atomic_counter_uniform_array_stride(0)
834e5c31af7Sopenharmony_ci	, m_gl_max_vertex_atomic_counters_value(0)
835e5c31af7Sopenharmony_ci	, m_helper_bo(0)
836e5c31af7Sopenharmony_ci	, m_helper_bo_size(0)
837e5c31af7Sopenharmony_ci	, m_helper_bo_size_rounded(0)
838e5c31af7Sopenharmony_ci	, m_n_draw_calls(3) /* as per test spec */
839e5c31af7Sopenharmony_ci	, m_page_size(page_size)
840e5c31af7Sopenharmony_ci	, m_po(0)
841e5c31af7Sopenharmony_ci	, m_sparse_bo(0)
842e5c31af7Sopenharmony_ci	, m_sparse_bo_data_size(0)
843e5c31af7Sopenharmony_ci	, m_sparse_bo_data_size_rounded(0)
844e5c31af7Sopenharmony_ci	, m_sparse_bo_data_start_offset(0)
845e5c31af7Sopenharmony_ci	, m_sparse_bo_data_start_offset_rounded(0)
846e5c31af7Sopenharmony_ci	, m_testCtx(testContext)
847e5c31af7Sopenharmony_ci	, m_vao(0)
848e5c31af7Sopenharmony_ci{
849e5c31af7Sopenharmony_ci	/* Left blank intentionally */
850e5c31af7Sopenharmony_ci}
851e5c31af7Sopenharmony_ci
852e5c31af7Sopenharmony_ci/** Releases all GL objects used across all test case iterations.
853e5c31af7Sopenharmony_ci *
854e5c31af7Sopenharmony_ci *  Called once during BufferStorage test run-time.
855e5c31af7Sopenharmony_ci */
856e5c31af7Sopenharmony_civoid AtomicCounterBufferStorageTestCase::deinitTestCaseGlobal()
857e5c31af7Sopenharmony_ci{
858e5c31af7Sopenharmony_ci	if (m_helper_bo != 0)
859e5c31af7Sopenharmony_ci	{
860e5c31af7Sopenharmony_ci		m_gl.deleteBuffers(1, &m_helper_bo);
861e5c31af7Sopenharmony_ci
862e5c31af7Sopenharmony_ci		m_helper_bo = 0;
863e5c31af7Sopenharmony_ci	}
864e5c31af7Sopenharmony_ci
865e5c31af7Sopenharmony_ci	if (m_po != 0)
866e5c31af7Sopenharmony_ci	{
867e5c31af7Sopenharmony_ci		m_gl.deleteProgram(m_po);
868e5c31af7Sopenharmony_ci
869e5c31af7Sopenharmony_ci		m_po = 0;
870e5c31af7Sopenharmony_ci	}
871e5c31af7Sopenharmony_ci
872e5c31af7Sopenharmony_ci	if (m_vao != 0)
873e5c31af7Sopenharmony_ci	{
874e5c31af7Sopenharmony_ci		m_gl.deleteVertexArrays(1, &m_vao);
875e5c31af7Sopenharmony_ci
876e5c31af7Sopenharmony_ci		m_vao = 0;
877e5c31af7Sopenharmony_ci	}
878e5c31af7Sopenharmony_ci}
879e5c31af7Sopenharmony_ci
880e5c31af7Sopenharmony_ci/** Releases temporary GL objects, created specifically for one test case iteration. */
881e5c31af7Sopenharmony_civoid AtomicCounterBufferStorageTestCase::deinitTestCaseIteration()
882e5c31af7Sopenharmony_ci{
883e5c31af7Sopenharmony_ci	if (m_sparse_bo != 0)
884e5c31af7Sopenharmony_ci	{
885e5c31af7Sopenharmony_ci		m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
886e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
887e5c31af7Sopenharmony_ci
888e5c31af7Sopenharmony_ci		m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, m_sparse_bo_data_start_offset_rounded,		/* offset */
889e5c31af7Sopenharmony_ci									 m_sparse_bo_data_size_rounded, GL_FALSE); /* commit */
890e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
891e5c31af7Sopenharmony_ci
892e5c31af7Sopenharmony_ci		m_sparse_bo = 0;
893e5c31af7Sopenharmony_ci	}
894e5c31af7Sopenharmony_ci}
895e5c31af7Sopenharmony_ci
896e5c31af7Sopenharmony_ci/** Executes a single test iteration. The BufferStorage test will call this method
897e5c31af7Sopenharmony_ci *  numerously during its life-time, testing various valid flag combinations applied
898e5c31af7Sopenharmony_ci *  to the tested sparse buffer object at glBufferStorage() call time.
899e5c31af7Sopenharmony_ci *
900e5c31af7Sopenharmony_ci *  @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage()
901e5c31af7Sopenharmony_ci *                                 call to set up the sparse buffer's storage.
902e5c31af7Sopenharmony_ci *
903e5c31af7Sopenharmony_ci *  @return true if the test case executed correctly, false otherwise.
904e5c31af7Sopenharmony_ci */
905e5c31af7Sopenharmony_cibool AtomicCounterBufferStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags)
906e5c31af7Sopenharmony_ci{
907e5c31af7Sopenharmony_ci	(void)sparse_bo_storage_flags;
908e5c31af7Sopenharmony_ci	static const unsigned char data_zero = 0;
909e5c31af7Sopenharmony_ci	bool					   result	= true;
910e5c31af7Sopenharmony_ci
911e5c31af7Sopenharmony_ci	/* Only execute if GL_MAX_VERTEX_ATOMIC_COUNTERS is > 0 */
912e5c31af7Sopenharmony_ci	if (m_gl_max_vertex_atomic_counters_value == 0)
913e5c31af7Sopenharmony_ci	{
914e5c31af7Sopenharmony_ci		m_testCtx.getLog() << tcu::TestLog::Message << "G_MAX_VERTEX_ATOMIC_COUNTERS is 0. Skipping the test."
915e5c31af7Sopenharmony_ci						   << tcu::TestLog::EndMessage;
916e5c31af7Sopenharmony_ci
917e5c31af7Sopenharmony_ci		goto end;
918e5c31af7Sopenharmony_ci	}
919e5c31af7Sopenharmony_ci
920e5c31af7Sopenharmony_ci	/* Bind the test program object */
921e5c31af7Sopenharmony_ci	m_gl.useProgram(m_po);
922e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() call failed.");
923e5c31af7Sopenharmony_ci
924e5c31af7Sopenharmony_ci	m_gl.bindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_sparse_bo);
925e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
926e5c31af7Sopenharmony_ci
927e5c31af7Sopenharmony_ci	/* Try using both ranged and non-ranged AC bindings.
928e5c31af7Sopenharmony_ci	 *
929e5c31af7Sopenharmony_ci	 * NOTE: It only makes sense to perform glBindBufferBase() test if all AC pages are
930e5c31af7Sopenharmony_ci	 *       committed
931e5c31af7Sopenharmony_ci	 */
932e5c31af7Sopenharmony_ci	for (unsigned int n_binding_type = (m_all_pages_committed) ? 0 : 1;
933e5c31af7Sopenharmony_ci		 n_binding_type < 2; /* glBindBufferBase(), glBindBufferRange() */
934e5c31af7Sopenharmony_ci		 ++n_binding_type)
935e5c31af7Sopenharmony_ci	{
936e5c31af7Sopenharmony_ci		bool result_local = true;
937e5c31af7Sopenharmony_ci
938e5c31af7Sopenharmony_ci		if (n_binding_type == 0)
939e5c31af7Sopenharmony_ci		{
940e5c31af7Sopenharmony_ci			m_gl.bindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, /* index */
941e5c31af7Sopenharmony_ci								m_sparse_bo);
942e5c31af7Sopenharmony_ci
943e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBufferBase() call failed.");
944e5c31af7Sopenharmony_ci		}
945e5c31af7Sopenharmony_ci		else
946e5c31af7Sopenharmony_ci		{
947e5c31af7Sopenharmony_ci			m_gl.bindBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, /* index */
948e5c31af7Sopenharmony_ci								 m_sparse_bo, m_sparse_bo_data_start_offset, m_helper_bo_size);
949e5c31af7Sopenharmony_ci
950e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBufferRange() call failed.");
951e5c31af7Sopenharmony_ci		}
952e5c31af7Sopenharmony_ci
953e5c31af7Sopenharmony_ci		/* Zero out the sparse buffer's contents */
954e5c31af7Sopenharmony_ci		m_gl.clearBufferData(GL_ATOMIC_COUNTER_BUFFER, GL_R8, GL_RED, GL_UNSIGNED_BYTE, &data_zero);
955e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glClearBufferData() call failed.");
956e5c31af7Sopenharmony_ci
957e5c31af7Sopenharmony_ci		/* Run the test */
958e5c31af7Sopenharmony_ci		m_gl.drawArraysInstanced(GL_POINTS, 0,							/* first */
959e5c31af7Sopenharmony_ci								 m_gl_max_vertex_atomic_counters_value, /* count */
960e5c31af7Sopenharmony_ci								 m_n_draw_calls);
961e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArraysInstanced() call failed");
962e5c31af7Sopenharmony_ci
963e5c31af7Sopenharmony_ci		/* Retrieve the atomic counter values */
964e5c31af7Sopenharmony_ci		const glw::GLuint* ac_data = NULL;
965e5c31af7Sopenharmony_ci		const unsigned int n_expected_written_values =
966e5c31af7Sopenharmony_ci			(m_all_pages_committed) ? m_gl_max_vertex_atomic_counters_value : m_gl_max_vertex_atomic_counters_value / 2;
967e5c31af7Sopenharmony_ci
968e5c31af7Sopenharmony_ci		m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_sparse_bo);
969e5c31af7Sopenharmony_ci		m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_helper_bo);
970e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffeR() call failed");
971e5c31af7Sopenharmony_ci
972e5c31af7Sopenharmony_ci		m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER,
973e5c31af7Sopenharmony_ci							   (n_binding_type == 0) ? 0 : m_sparse_bo_data_start_offset, 0, /* writeOffset */
974e5c31af7Sopenharmony_ci							   m_sparse_bo_data_size);
975e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
976e5c31af7Sopenharmony_ci
977e5c31af7Sopenharmony_ci		ac_data = (const glw::GLuint*)m_gl.mapBufferRange(GL_COPY_WRITE_BUFFER, 0, /* offset */
978e5c31af7Sopenharmony_ci														  m_sparse_bo_data_size, GL_MAP_READ_BIT);
979e5c31af7Sopenharmony_ci
980e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMapBufferRange() call failed.");
981e5c31af7Sopenharmony_ci
982e5c31af7Sopenharmony_ci		for (unsigned int n_counter = 0; n_counter < n_expected_written_values && result_local; ++n_counter)
983e5c31af7Sopenharmony_ci		{
984e5c31af7Sopenharmony_ci			const unsigned int expected_value = m_n_draw_calls;
985e5c31af7Sopenharmony_ci			const unsigned int retrieved_value =
986e5c31af7Sopenharmony_ci				*((unsigned int*)((unsigned char*)ac_data + m_gl_atomic_counter_uniform_array_stride * n_counter));
987e5c31af7Sopenharmony_ci
988e5c31af7Sopenharmony_ci			if (expected_value != retrieved_value)
989e5c31af7Sopenharmony_ci			{
990e5c31af7Sopenharmony_ci				m_testCtx.getLog() << tcu::TestLog::Message << "Invalid atomic counter value "
991e5c31af7Sopenharmony_ci															   "["
992e5c31af7Sopenharmony_ci								   << retrieved_value << "]"
993e5c31af7Sopenharmony_ci														 " instead of the expected value "
994e5c31af7Sopenharmony_ci														 "["
995e5c31af7Sopenharmony_ci								   << expected_value << "]"
996e5c31af7Sopenharmony_ci														" at index "
997e5c31af7Sopenharmony_ci								   << n_counter << " when using "
998e5c31af7Sopenharmony_ci								   << ((n_binding_type == 0) ? "glBindBufferBase()" : "glBindBufferRange()")
999e5c31af7Sopenharmony_ci								   << " for AC binding configuration" << tcu::TestLog::EndMessage;
1000e5c31af7Sopenharmony_ci
1001e5c31af7Sopenharmony_ci				result_local = false;
1002e5c31af7Sopenharmony_ci			} /* if (expected_value != retrieved_value) */
1003e5c31af7Sopenharmony_ci		}	 /* for (all draw calls that need to be executed) */
1004e5c31af7Sopenharmony_ci
1005e5c31af7Sopenharmony_ci		m_gl.unmapBuffer(GL_COPY_WRITE_BUFFER);
1006e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUnmapBuffer() call failed.");
1007e5c31af7Sopenharmony_ci
1008e5c31af7Sopenharmony_ci		result &= result_local;
1009e5c31af7Sopenharmony_ci	} /* for (both binding types) */
1010e5c31af7Sopenharmony_ci
1011e5c31af7Sopenharmony_ciend:
1012e5c31af7Sopenharmony_ci	return result;
1013e5c31af7Sopenharmony_ci}
1014e5c31af7Sopenharmony_ci
1015e5c31af7Sopenharmony_ci/** Initializes GL objects used across all test case iterations.
1016e5c31af7Sopenharmony_ci *
1017e5c31af7Sopenharmony_ci *  Called once during BufferStorage test run-time.
1018e5c31af7Sopenharmony_ci */
1019e5c31af7Sopenharmony_cibool AtomicCounterBufferStorageTestCase::initTestCaseGlobal()
1020e5c31af7Sopenharmony_ci{
1021e5c31af7Sopenharmony_ci	const glw::GLuint ac_uniform_index = 0; /* only one uniform is defined in the VS below */
1022e5c31af7Sopenharmony_ci	std::stringstream n_counters_sstream;
1023e5c31af7Sopenharmony_ci	std::string		  n_counters_string;
1024e5c31af7Sopenharmony_ci	bool			  result = true;
1025e5c31af7Sopenharmony_ci
1026e5c31af7Sopenharmony_ci	static const char* vs_body_preamble = "#version 430 core\n"
1027e5c31af7Sopenharmony_ci										  "\n";
1028e5c31af7Sopenharmony_ci
1029e5c31af7Sopenharmony_ci	static const char* vs_body_core = "layout(binding = 0) uniform atomic_uint counters[N_COUNTERS];\n"
1030e5c31af7Sopenharmony_ci									  "\n"
1031e5c31af7Sopenharmony_ci									  "void main()\n"
1032e5c31af7Sopenharmony_ci									  "{\n"
1033e5c31af7Sopenharmony_ci									  "    for (uint n = 0; n < N_COUNTERS; ++n)\n"
1034e5c31af7Sopenharmony_ci									  "    {\n"
1035e5c31af7Sopenharmony_ci									  "        if (n == gl_VertexID)\n"
1036e5c31af7Sopenharmony_ci									  "        {\n"
1037e5c31af7Sopenharmony_ci									  "            atomicCounterIncrement(counters[n]);\n"
1038e5c31af7Sopenharmony_ci									  "        }\n"
1039e5c31af7Sopenharmony_ci									  "    }\n"
1040e5c31af7Sopenharmony_ci									  "\n"
1041e5c31af7Sopenharmony_ci									  "    gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n"
1042e5c31af7Sopenharmony_ci									  "}\n";
1043e5c31af7Sopenharmony_ci	const char* vs_body_parts[] = { vs_body_preamble, DE_NULL, /* will be set to n_counters_string.c_str() */
1044e5c31af7Sopenharmony_ci									vs_body_core };
1045e5c31af7Sopenharmony_ci	const unsigned int n_vs_body_parts = sizeof(vs_body_parts) / sizeof(vs_body_parts[0]);
1046e5c31af7Sopenharmony_ci
1047e5c31af7Sopenharmony_ci	/* Retrieve GL_MAX_VERTEX_ATOMIC_COUNTERS value. The test will only be executed if it's >= 1 */
1048e5c31af7Sopenharmony_ci	m_gl.getIntegerv(GL_MAX_VERTEX_ATOMIC_COUNTERS, &m_gl_max_vertex_atomic_counters_value);
1049e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetIntegerv() call failed.");
1050e5c31af7Sopenharmony_ci
1051e5c31af7Sopenharmony_ci	if (m_gl_max_vertex_atomic_counters_value == 0)
1052e5c31af7Sopenharmony_ci	{
1053e5c31af7Sopenharmony_ci		goto end;
1054e5c31af7Sopenharmony_ci	}
1055e5c31af7Sopenharmony_ci
1056e5c31af7Sopenharmony_ci	/* Form the N_COUNTERS declaration string */
1057e5c31af7Sopenharmony_ci	n_counters_sstream << "#define N_COUNTERS " << m_gl_max_vertex_atomic_counters_value << "\n";
1058e5c31af7Sopenharmony_ci	n_counters_string = n_counters_sstream.str();
1059e5c31af7Sopenharmony_ci
1060e5c31af7Sopenharmony_ci	vs_body_parts[1] = n_counters_string.c_str();
1061e5c31af7Sopenharmony_ci
1062e5c31af7Sopenharmony_ci	/* Set up the program object */
1063e5c31af7Sopenharmony_ci	DE_ASSERT(m_po == 0);
1064e5c31af7Sopenharmony_ci
1065e5c31af7Sopenharmony_ci	m_po =
1066e5c31af7Sopenharmony_ci		SparseBufferTestUtilities::createProgram(m_gl, DE_NULL,							  /* fs_body_parts   */
1067e5c31af7Sopenharmony_ci												 0,										  /* n_fs_body_parts */
1068e5c31af7Sopenharmony_ci												 vs_body_parts, n_vs_body_parts, DE_NULL, /* attribute_names        */
1069e5c31af7Sopenharmony_ci												 DE_NULL,								  /* attribute_locations    */
1070e5c31af7Sopenharmony_ci												 0);									  /* n_attribute_properties */
1071e5c31af7Sopenharmony_ci
1072e5c31af7Sopenharmony_ci	if (m_po == 0)
1073e5c31af7Sopenharmony_ci	{
1074e5c31af7Sopenharmony_ci		result = false;
1075e5c31af7Sopenharmony_ci
1076e5c31af7Sopenharmony_ci		goto end;
1077e5c31af7Sopenharmony_ci	}
1078e5c31af7Sopenharmony_ci
1079e5c31af7Sopenharmony_ci	/* Helper BO will be used to hold the atomic counter buffer data.
1080e5c31af7Sopenharmony_ci	 * Determine how much space will be needed.
1081e5c31af7Sopenharmony_ci	 *
1082e5c31af7Sopenharmony_ci	 * Min max for the GL constant value is 0. Bail out if that's the
1083e5c31af7Sopenharmony_ci	 * value we are returned - it is pointless to execute the test in
1084e5c31af7Sopenharmony_ci	 * such environment.
1085e5c31af7Sopenharmony_ci	 */
1086e5c31af7Sopenharmony_ci	m_gl.getActiveUniformsiv(m_po, 1, /* uniformCount */
1087e5c31af7Sopenharmony_ci							 &ac_uniform_index, GL_UNIFORM_ARRAY_STRIDE, &m_gl_atomic_counter_uniform_array_stride);
1088e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetActiveUniformsiv() call failed.");
1089e5c31af7Sopenharmony_ci
1090e5c31af7Sopenharmony_ci	DE_ASSERT(m_gl_atomic_counter_uniform_array_stride >= (int)sizeof(unsigned int));
1091e5c31af7Sopenharmony_ci
1092e5c31af7Sopenharmony_ci	m_helper_bo_size		 = m_gl_atomic_counter_uniform_array_stride * m_gl_max_vertex_atomic_counters_value;
1093e5c31af7Sopenharmony_ci	m_helper_bo_size_rounded = SparseBufferTestUtilities::alignOffset(m_helper_bo_size, m_page_size);
1094e5c31af7Sopenharmony_ci
1095e5c31af7Sopenharmony_ci	/* Set up the helper BO */
1096e5c31af7Sopenharmony_ci	DE_ASSERT(m_helper_bo == 0);
1097e5c31af7Sopenharmony_ci
1098e5c31af7Sopenharmony_ci	m_gl.genBuffers(1, &m_helper_bo);
1099e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
1100e5c31af7Sopenharmony_ci
1101e5c31af7Sopenharmony_ci	m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
1102e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
1103e5c31af7Sopenharmony_ci
1104e5c31af7Sopenharmony_ci	m_gl.bufferStorage(GL_COPY_READ_BUFFER, m_helper_bo_size_rounded, DE_NULL, GL_MAP_READ_BIT); /* flags */
1105e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed.");
1106e5c31af7Sopenharmony_ci
1107e5c31af7Sopenharmony_ci	/* Set up the vertex array object */
1108e5c31af7Sopenharmony_ci	DE_ASSERT(m_vao == 0);
1109e5c31af7Sopenharmony_ci
1110e5c31af7Sopenharmony_ci	m_gl.genVertexArrays(1, &m_vao);
1111e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenVertexArrays() call failed.");
1112e5c31af7Sopenharmony_ci
1113e5c31af7Sopenharmony_ci	m_gl.bindVertexArray(m_vao);
1114e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindVertexArray() call failed.");
1115e5c31af7Sopenharmony_ci
1116e5c31af7Sopenharmony_ciend:
1117e5c31af7Sopenharmony_ci	return result;
1118e5c31af7Sopenharmony_ci}
1119e5c31af7Sopenharmony_ci
1120e5c31af7Sopenharmony_ci/** Initializes GL objects which are needed for a single test case iteration.
1121e5c31af7Sopenharmony_ci *
1122e5c31af7Sopenharmony_ci *  deinitTestCaseIteration() will be called after the test case is executed in ::execute()
1123e5c31af7Sopenharmony_ci *  to release these objects.
1124e5c31af7Sopenharmony_ci **/
1125e5c31af7Sopenharmony_cibool AtomicCounterBufferStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo)
1126e5c31af7Sopenharmony_ci{
1127e5c31af7Sopenharmony_ci	bool result = true;
1128e5c31af7Sopenharmony_ci
1129e5c31af7Sopenharmony_ci	/* Cache the BO id, if not cached already */
1130e5c31af7Sopenharmony_ci	DE_ASSERT(m_sparse_bo == 0 || m_sparse_bo == sparse_bo);
1131e5c31af7Sopenharmony_ci
1132e5c31af7Sopenharmony_ci	m_sparse_bo = sparse_bo;
1133e5c31af7Sopenharmony_ci
1134e5c31af7Sopenharmony_ci	/* Set up the sparse bufffer. */
1135e5c31af7Sopenharmony_ci	int sparse_bo_data_size = 0;
1136e5c31af7Sopenharmony_ci
1137e5c31af7Sopenharmony_ci	DE_ASSERT(m_helper_bo_size_rounded != 0);
1138e5c31af7Sopenharmony_ci
1139e5c31af7Sopenharmony_ci	m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
1140e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
1141e5c31af7Sopenharmony_ci
1142e5c31af7Sopenharmony_ci	if (m_all_pages_committed)
1143e5c31af7Sopenharmony_ci	{
1144e5c31af7Sopenharmony_ci		/* Commit all required pages */
1145e5c31af7Sopenharmony_ci		sparse_bo_data_size = m_helper_bo_size_rounded;
1146e5c31af7Sopenharmony_ci	}
1147e5c31af7Sopenharmony_ci	else
1148e5c31af7Sopenharmony_ci	{
1149e5c31af7Sopenharmony_ci		/* Only commit the first half of the required pages */
1150e5c31af7Sopenharmony_ci		DE_ASSERT((m_helper_bo_size_rounded % m_page_size) == 0);
1151e5c31af7Sopenharmony_ci
1152e5c31af7Sopenharmony_ci		sparse_bo_data_size = (m_helper_bo_size_rounded / m_page_size) * m_page_size / 2;
1153e5c31af7Sopenharmony_ci	}
1154e5c31af7Sopenharmony_ci
1155e5c31af7Sopenharmony_ci	/* NOTE: We need to ensure that the memory region assigned to the atomic counter buffer spans
1156e5c31af7Sopenharmony_ci	 *       at least through two separate pages.
1157e5c31af7Sopenharmony_ci	 *
1158e5c31af7Sopenharmony_ci	 * Since we align up, we need to move one page backward and then apply the alignment function
1159e5c31af7Sopenharmony_ci	 * to determine the start page index.
1160e5c31af7Sopenharmony_ci	 */
1161e5c31af7Sopenharmony_ci	const int sparse_bo_data_start_offset			 = m_page_size - m_helper_bo_size_rounded / 2;
1162e5c31af7Sopenharmony_ci	int		  sparse_bo_data_start_offset_minus_page = sparse_bo_data_start_offset - m_page_size;
1163e5c31af7Sopenharmony_ci
1164e5c31af7Sopenharmony_ci	if (sparse_bo_data_start_offset_minus_page < 0)
1165e5c31af7Sopenharmony_ci	{
1166e5c31af7Sopenharmony_ci		sparse_bo_data_start_offset_minus_page = 0;
1167e5c31af7Sopenharmony_ci	}
1168e5c31af7Sopenharmony_ci
1169e5c31af7Sopenharmony_ci	m_sparse_bo_data_start_offset = sparse_bo_data_start_offset;
1170e5c31af7Sopenharmony_ci	m_sparse_bo_data_start_offset_rounded =
1171e5c31af7Sopenharmony_ci		SparseBufferTestUtilities::alignOffset(sparse_bo_data_start_offset_minus_page, m_page_size);
1172e5c31af7Sopenharmony_ci	m_sparse_bo_data_size = sparse_bo_data_size;
1173e5c31af7Sopenharmony_ci	m_sparse_bo_data_size_rounded =
1174e5c31af7Sopenharmony_ci		SparseBufferTestUtilities::alignOffset(m_sparse_bo_data_start_offset + sparse_bo_data_size, m_page_size);
1175e5c31af7Sopenharmony_ci
1176e5c31af7Sopenharmony_ci	DE_ASSERT((m_sparse_bo_data_size_rounded % m_page_size) == 0);
1177e5c31af7Sopenharmony_ci	DE_ASSERT((m_sparse_bo_data_start_offset_rounded % m_page_size) == 0);
1178e5c31af7Sopenharmony_ci
1179e5c31af7Sopenharmony_ci	m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, m_sparse_bo_data_start_offset_rounded, m_sparse_bo_data_size_rounded,
1180e5c31af7Sopenharmony_ci								 GL_TRUE); /* commit */
1181e5c31af7Sopenharmony_ci
1182e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
1183e5c31af7Sopenharmony_ci
1184e5c31af7Sopenharmony_ci	return result;
1185e5c31af7Sopenharmony_ci}
1186e5c31af7Sopenharmony_ci
1187e5c31af7Sopenharmony_ci/** Constructor.
1188e5c31af7Sopenharmony_ci *
1189e5c31af7Sopenharmony_ci *  @param gl                         GL entry-points container
1190e5c31af7Sopenharmony_ci *  @param context                    CTS rendering context
1191e5c31af7Sopenharmony_ci *  @param testContext                CTS test context
1192e5c31af7Sopenharmony_ci *  @param page_size                  Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query.
1193e5c31af7Sopenharmony_ci *  @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point.
1194e5c31af7Sopenharmony_ci */
1195e5c31af7Sopenharmony_ciBufferTextureStorageTestCase::BufferTextureStorageTestCase(const glw::Functions& gl, deqp::Context& context,
1196e5c31af7Sopenharmony_ci														   tcu::TestContext& testContext, glw::GLint page_size)
1197e5c31af7Sopenharmony_ci	: m_gl(gl)
1198e5c31af7Sopenharmony_ci	, m_helper_bo(0)
1199e5c31af7Sopenharmony_ci	, m_helper_bo_data(DE_NULL)
1200e5c31af7Sopenharmony_ci	, m_helper_bo_data_size(0)
1201e5c31af7Sopenharmony_ci	, m_is_texture_buffer_range_supported(false)
1202e5c31af7Sopenharmony_ci	, m_page_size(page_size)
1203e5c31af7Sopenharmony_ci	, m_po(0)
1204e5c31af7Sopenharmony_ci	, m_po_local_wg_size(1024)
1205e5c31af7Sopenharmony_ci	, m_sparse_bo(0)
1206e5c31af7Sopenharmony_ci	, m_sparse_bo_size(0)
1207e5c31af7Sopenharmony_ci	, m_sparse_bo_size_rounded(0)
1208e5c31af7Sopenharmony_ci	, m_ssbo(0)
1209e5c31af7Sopenharmony_ci	, m_ssbo_zero_data(DE_NULL)
1210e5c31af7Sopenharmony_ci	, m_ssbo_zero_data_size(0)
1211e5c31af7Sopenharmony_ci	, m_testCtx(testContext)
1212e5c31af7Sopenharmony_ci	, m_to(0)
1213e5c31af7Sopenharmony_ci	, m_to_width(65536) /* min max for GL_MAX_TEXTURE_BUFFER_SIZE_ARB */
1214e5c31af7Sopenharmony_ci{
1215e5c31af7Sopenharmony_ci	const glu::ContextInfo& context_info   = context.getContextInfo();
1216e5c31af7Sopenharmony_ci	glu::RenderContext&		render_context = context.getRenderContext();
1217e5c31af7Sopenharmony_ci
1218e5c31af7Sopenharmony_ci	if (glu::contextSupports(render_context.getType(), glu::ApiType::core(4, 3)) ||
1219e5c31af7Sopenharmony_ci		context_info.isExtensionSupported("GL_ARB_texture_buffer_range"))
1220e5c31af7Sopenharmony_ci	{
1221e5c31af7Sopenharmony_ci		m_is_texture_buffer_range_supported = true;
1222e5c31af7Sopenharmony_ci	}
1223e5c31af7Sopenharmony_ci}
1224e5c31af7Sopenharmony_ci
1225e5c31af7Sopenharmony_ci/** Releases all GL objects used across all test case iterations.
1226e5c31af7Sopenharmony_ci *
1227e5c31af7Sopenharmony_ci *  Called once during BufferStorage test run-time.
1228e5c31af7Sopenharmony_ci */
1229e5c31af7Sopenharmony_civoid BufferTextureStorageTestCase::deinitTestCaseGlobal()
1230e5c31af7Sopenharmony_ci{
1231e5c31af7Sopenharmony_ci	if (m_helper_bo != 0)
1232e5c31af7Sopenharmony_ci	{
1233e5c31af7Sopenharmony_ci		m_gl.deleteBuffers(1, &m_helper_bo);
1234e5c31af7Sopenharmony_ci
1235e5c31af7Sopenharmony_ci		m_helper_bo = 0;
1236e5c31af7Sopenharmony_ci	}
1237e5c31af7Sopenharmony_ci
1238e5c31af7Sopenharmony_ci	if (m_helper_bo_data != DE_NULL)
1239e5c31af7Sopenharmony_ci	{
1240e5c31af7Sopenharmony_ci		delete[] m_helper_bo_data;
1241e5c31af7Sopenharmony_ci
1242e5c31af7Sopenharmony_ci		m_helper_bo_data = DE_NULL;
1243e5c31af7Sopenharmony_ci	}
1244e5c31af7Sopenharmony_ci
1245e5c31af7Sopenharmony_ci	if (m_po != 0)
1246e5c31af7Sopenharmony_ci	{
1247e5c31af7Sopenharmony_ci		m_gl.deleteProgram(m_po);
1248e5c31af7Sopenharmony_ci
1249e5c31af7Sopenharmony_ci		m_po = 0;
1250e5c31af7Sopenharmony_ci	}
1251e5c31af7Sopenharmony_ci
1252e5c31af7Sopenharmony_ci	if (m_ssbo != 0)
1253e5c31af7Sopenharmony_ci	{
1254e5c31af7Sopenharmony_ci		m_gl.deleteBuffers(1, &m_ssbo);
1255e5c31af7Sopenharmony_ci
1256e5c31af7Sopenharmony_ci		m_ssbo = 0;
1257e5c31af7Sopenharmony_ci	}
1258e5c31af7Sopenharmony_ci
1259e5c31af7Sopenharmony_ci	if (m_ssbo_zero_data != DE_NULL)
1260e5c31af7Sopenharmony_ci	{
1261e5c31af7Sopenharmony_ci		delete[] m_ssbo_zero_data;
1262e5c31af7Sopenharmony_ci
1263e5c31af7Sopenharmony_ci		m_ssbo_zero_data = DE_NULL;
1264e5c31af7Sopenharmony_ci	}
1265e5c31af7Sopenharmony_ci
1266e5c31af7Sopenharmony_ci	if (m_to != 0)
1267e5c31af7Sopenharmony_ci	{
1268e5c31af7Sopenharmony_ci		m_gl.deleteTextures(1, &m_to);
1269e5c31af7Sopenharmony_ci
1270e5c31af7Sopenharmony_ci		m_to = 0;
1271e5c31af7Sopenharmony_ci	}
1272e5c31af7Sopenharmony_ci}
1273e5c31af7Sopenharmony_ci
1274e5c31af7Sopenharmony_ci/** Releases temporary GL objects, created specifically for one test case iteration. */
1275e5c31af7Sopenharmony_civoid BufferTextureStorageTestCase::deinitTestCaseIteration()
1276e5c31af7Sopenharmony_ci{
1277e5c31af7Sopenharmony_ci	if (m_sparse_bo != 0)
1278e5c31af7Sopenharmony_ci	{
1279e5c31af7Sopenharmony_ci		m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
1280e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
1281e5c31af7Sopenharmony_ci
1282e5c31af7Sopenharmony_ci		m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,				  /* offset */
1283e5c31af7Sopenharmony_ci									 m_sparse_bo_size_rounded, GL_FALSE); /* commit */
1284e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
1285e5c31af7Sopenharmony_ci
1286e5c31af7Sopenharmony_ci		m_sparse_bo = 0;
1287e5c31af7Sopenharmony_ci	}
1288e5c31af7Sopenharmony_ci}
1289e5c31af7Sopenharmony_ci
1290e5c31af7Sopenharmony_ci/** Executes a single test iteration. The BufferStorage test will call this method
1291e5c31af7Sopenharmony_ci *  numerously during its life-time, testing various valid flag combinations applied
1292e5c31af7Sopenharmony_ci *  to the tested sparse buffer object at glBufferStorage() call time.
1293e5c31af7Sopenharmony_ci *
1294e5c31af7Sopenharmony_ci *  @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage()
1295e5c31af7Sopenharmony_ci *                                 call to set up the sparse buffer's storage.
1296e5c31af7Sopenharmony_ci *
1297e5c31af7Sopenharmony_ci *  @return true if the test case executed correctly, false otherwise.
1298e5c31af7Sopenharmony_ci */
1299e5c31af7Sopenharmony_cibool BufferTextureStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags)
1300e5c31af7Sopenharmony_ci{
1301e5c31af7Sopenharmony_ci	(void)sparse_bo_storage_flags;
1302e5c31af7Sopenharmony_ci	bool result = true;
1303e5c31af7Sopenharmony_ci
1304e5c31af7Sopenharmony_ci	/* Bind the program object */
1305e5c31af7Sopenharmony_ci	m_gl.useProgram(m_po);
1306e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() call failed.");
1307e5c31af7Sopenharmony_ci
1308e5c31af7Sopenharmony_ci	m_gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, m_ssbo);
1309e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
1310e5c31af7Sopenharmony_ci
1311e5c31af7Sopenharmony_ci	m_gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, /* index */
1312e5c31af7Sopenharmony_ci						m_ssbo);
1313e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBufferBase() call failed.");
1314e5c31af7Sopenharmony_ci
1315e5c31af7Sopenharmony_ci	/* Set up bindings for the copy ops */
1316e5c31af7Sopenharmony_ci	m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
1317e5c31af7Sopenharmony_ci	m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_sparse_bo);
1318e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call(s) failed.");
1319e5c31af7Sopenharmony_ci
1320e5c31af7Sopenharmony_ci	/* Run the test in two iterations:
1321e5c31af7Sopenharmony_ci	 *
1322e5c31af7Sopenharmony_ci	 * a) All required pages are committed.
1323e5c31af7Sopenharmony_ci	 * b) Only half of the pages are committed. */
1324e5c31af7Sopenharmony_ci	for (unsigned int n_iteration = 0; n_iteration < 2; ++n_iteration)
1325e5c31af7Sopenharmony_ci	{
1326e5c31af7Sopenharmony_ci
1327e5c31af7Sopenharmony_ci		/* Test glTexBuffer() and glTexBufferRange() separately. */
1328e5c31af7Sopenharmony_ci		for (int n_entry_point = 0; n_entry_point < (m_is_texture_buffer_range_supported ? 2 : 1); ++n_entry_point)
1329e5c31af7Sopenharmony_ci		{
1330e5c31af7Sopenharmony_ci			bool result_local = true;
1331e5c31af7Sopenharmony_ci
1332e5c31af7Sopenharmony_ci			/* Set up the sparse buffer's memory backing. */
1333e5c31af7Sopenharmony_ci			const unsigned int tbo_commit_start_offset = (n_iteration == 0) ? 0 : m_sparse_bo_size_rounded / 2;
1334e5c31af7Sopenharmony_ci			const unsigned int tbo_commit_size =
1335e5c31af7Sopenharmony_ci				(n_iteration == 0) ? m_sparse_bo_size_rounded : m_sparse_bo_size_rounded / 2;
1336e5c31af7Sopenharmony_ci
1337e5c31af7Sopenharmony_ci			m_gl.bindBuffer(GL_TEXTURE_BUFFER, m_sparse_bo);
1338e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
1339e5c31af7Sopenharmony_ci
1340e5c31af7Sopenharmony_ci			m_gl.bufferPageCommitmentARB(GL_TEXTURE_BUFFER, tbo_commit_start_offset, tbo_commit_size,
1341e5c31af7Sopenharmony_ci										 GL_TRUE); /* commit */
1342e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
1343e5c31af7Sopenharmony_ci
1344e5c31af7Sopenharmony_ci			/* Set up the buffer texture's backing */
1345e5c31af7Sopenharmony_ci			if (n_entry_point == 0)
1346e5c31af7Sopenharmony_ci			{
1347e5c31af7Sopenharmony_ci				m_gl.texBuffer(GL_TEXTURE_BUFFER, GL_RGBA8, m_sparse_bo);
1348e5c31af7Sopenharmony_ci
1349e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glTexBuffer() call failed.");
1350e5c31af7Sopenharmony_ci			}
1351e5c31af7Sopenharmony_ci			else
1352e5c31af7Sopenharmony_ci			{
1353e5c31af7Sopenharmony_ci				m_gl.texBufferRange(GL_TEXTURE_BUFFER, GL_RGBA8, m_sparse_bo, 0, /* offset */
1354e5c31af7Sopenharmony_ci									m_sparse_bo_size);
1355e5c31af7Sopenharmony_ci
1356e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glTexBufferRange() call failed.");
1357e5c31af7Sopenharmony_ci			}
1358e5c31af7Sopenharmony_ci
1359e5c31af7Sopenharmony_ci			/* Set up the sparse buffer's data storage */
1360e5c31af7Sopenharmony_ci			m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, /* readOffset */
1361e5c31af7Sopenharmony_ci								   0,											 /* writeOffset */
1362e5c31af7Sopenharmony_ci								   m_helper_bo_data_size);
1363e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
1364e5c31af7Sopenharmony_ci
1365e5c31af7Sopenharmony_ci			/* Run the compute program */
1366e5c31af7Sopenharmony_ci			DE_ASSERT((m_to_width % m_po_local_wg_size) == 0);
1367e5c31af7Sopenharmony_ci
1368e5c31af7Sopenharmony_ci			m_gl.dispatchCompute(m_to_width / m_po_local_wg_size, 1, /* num_groups_y */
1369e5c31af7Sopenharmony_ci								 1);								 /* num_groups_z */
1370e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDispatchCompute() call failed.");
1371e5c31af7Sopenharmony_ci
1372e5c31af7Sopenharmony_ci			/* Flush the caches */
1373e5c31af7Sopenharmony_ci			m_gl.memoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
1374e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMemoryBarrier() call failed.");
1375e5c31af7Sopenharmony_ci
1376e5c31af7Sopenharmony_ci			/* Map the SSBO into process space, so we can check if the texture buffer's
1377e5c31af7Sopenharmony_ci			 * contents was found valid by the compute shader */
1378e5c31af7Sopenharmony_ci			unsigned int		current_tb_offset = 0;
1379e5c31af7Sopenharmony_ci			const unsigned int* ssbo_data_ptr =
1380e5c31af7Sopenharmony_ci				(const unsigned int*)m_gl.mapBuffer(GL_SHADER_STORAGE_BUFFER, GL_READ_ONLY);
1381e5c31af7Sopenharmony_ci
1382e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMapBuffer() call failed.");
1383e5c31af7Sopenharmony_ci
1384e5c31af7Sopenharmony_ci			for (unsigned int n_texel = 0; n_texel < m_to_width && result_local;
1385e5c31af7Sopenharmony_ci				 ++n_texel, current_tb_offset += 4 /* rgba */)
1386e5c31af7Sopenharmony_ci			{
1387e5c31af7Sopenharmony_ci				/* NOTE: Since the CS uses std140 layout, we need to move by 4 ints for
1388e5c31af7Sopenharmony_ci				 *       each result value */
1389e5c31af7Sopenharmony_ci				if (current_tb_offset >= tbo_commit_start_offset &&
1390e5c31af7Sopenharmony_ci					current_tb_offset < (tbo_commit_start_offset + tbo_commit_size) && ssbo_data_ptr[n_texel * 4] != 1)
1391e5c31af7Sopenharmony_ci				{
1392e5c31af7Sopenharmony_ci					m_testCtx.getLog() << tcu::TestLog::Message << "A texel read from the texture buffer at index "
1393e5c31af7Sopenharmony_ci																   "["
1394e5c31af7Sopenharmony_ci									   << n_texel << "]"
1395e5c31af7Sopenharmony_ci													 " was marked as invalid by the CS invocation."
1396e5c31af7Sopenharmony_ci									   << tcu::TestLog::EndMessage;
1397e5c31af7Sopenharmony_ci
1398e5c31af7Sopenharmony_ci					result_local = false;
1399e5c31af7Sopenharmony_ci				} /* if (ssbo_data_ptr[n_texel] != 1) */
1400e5c31af7Sopenharmony_ci			}	 /* for (all result values) */
1401e5c31af7Sopenharmony_ci
1402e5c31af7Sopenharmony_ci			result &= result_local;
1403e5c31af7Sopenharmony_ci
1404e5c31af7Sopenharmony_ci			m_gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER);
1405e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUnmapBuffer() call failed.");
1406e5c31af7Sopenharmony_ci
1407e5c31af7Sopenharmony_ci			/* Remove the physical backing from the sparse buffer  */
1408e5c31af7Sopenharmony_ci			m_gl.bufferPageCommitmentARB(GL_TEXTURE_BUFFER, 0,				  /* offset */
1409e5c31af7Sopenharmony_ci										 m_sparse_bo_size_rounded, GL_FALSE); /* commit */
1410e5c31af7Sopenharmony_ci
1411e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
1412e5c31af7Sopenharmony_ci
1413e5c31af7Sopenharmony_ci			/* Reset SSBO's contents */
1414e5c31af7Sopenharmony_ci			m_gl.bufferSubData(GL_SHADER_STORAGE_BUFFER, 0, /* offset */
1415e5c31af7Sopenharmony_ci							   m_ssbo_zero_data_size, m_ssbo_zero_data);
1416e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferSubData() call failed.");
1417e5c31af7Sopenharmony_ci		} /* for (both entry-points) */
1418e5c31af7Sopenharmony_ci	}	 /* for (both iterations) */
1419e5c31af7Sopenharmony_ci
1420e5c31af7Sopenharmony_ci	return result;
1421e5c31af7Sopenharmony_ci}
1422e5c31af7Sopenharmony_ci
1423e5c31af7Sopenharmony_ci/** Initializes GL objects used across all test case iterations.
1424e5c31af7Sopenharmony_ci *
1425e5c31af7Sopenharmony_ci *  Called once during BufferStorage test run-time.
1426e5c31af7Sopenharmony_ci */
1427e5c31af7Sopenharmony_cibool BufferTextureStorageTestCase::initTestCaseGlobal()
1428e5c31af7Sopenharmony_ci{
1429e5c31af7Sopenharmony_ci	/* Set up the test program */
1430e5c31af7Sopenharmony_ci	static const char* cs_body =
1431e5c31af7Sopenharmony_ci		"#version 430 core\n"
1432e5c31af7Sopenharmony_ci		"\n"
1433e5c31af7Sopenharmony_ci		"layout(local_size_x = 1024) in;\n"
1434e5c31af7Sopenharmony_ci		"\n"
1435e5c31af7Sopenharmony_ci		"layout(std140, binding = 0) buffer data\n"
1436e5c31af7Sopenharmony_ci		"{\n"
1437e5c31af7Sopenharmony_ci		"    restrict writeonly int result[];\n"
1438e5c31af7Sopenharmony_ci		"};\n"
1439e5c31af7Sopenharmony_ci		"\n"
1440e5c31af7Sopenharmony_ci		"uniform samplerBuffer input_texture;\n"
1441e5c31af7Sopenharmony_ci		"\n"
1442e5c31af7Sopenharmony_ci		"void main()\n"
1443e5c31af7Sopenharmony_ci		"{\n"
1444e5c31af7Sopenharmony_ci		"    uint texel_index = gl_GlobalInvocationID.x;\n"
1445e5c31af7Sopenharmony_ci		"\n"
1446e5c31af7Sopenharmony_ci		"    if (texel_index < 65536)\n"
1447e5c31af7Sopenharmony_ci		"    {\n"
1448e5c31af7Sopenharmony_ci		"        vec4 expected_texel_data = vec4       (float((texel_index)       % 255) / 255.0,\n"
1449e5c31af7Sopenharmony_ci		"                                               float((texel_index + 35)  % 255) / 255.0,\n"
1450e5c31af7Sopenharmony_ci		"                                               float((texel_index + 78)  % 255) / 255.0,\n"
1451e5c31af7Sopenharmony_ci		"                                               float((texel_index + 131) % 255) / 255.0);\n"
1452e5c31af7Sopenharmony_ci		"        vec4 texel_data          = texelFetch(input_texture, int(texel_index) );\n"
1453e5c31af7Sopenharmony_ci		"\n"
1454e5c31af7Sopenharmony_ci		"        if (abs(texel_data.r - expected_texel_data.r) > 1.0 / 255.0 ||\n"
1455e5c31af7Sopenharmony_ci		"            abs(texel_data.g - expected_texel_data.g) > 1.0 / 255.0 ||\n"
1456e5c31af7Sopenharmony_ci		"            abs(texel_data.b - expected_texel_data.b) > 1.0 / 255.0 ||\n"
1457e5c31af7Sopenharmony_ci		"            abs(texel_data.a - expected_texel_data.a) > 1.0 / 255.0)\n"
1458e5c31af7Sopenharmony_ci		"        {\n"
1459e5c31af7Sopenharmony_ci		"            result[texel_index] = 0;\n"
1460e5c31af7Sopenharmony_ci		"        }\n"
1461e5c31af7Sopenharmony_ci		"        else\n"
1462e5c31af7Sopenharmony_ci		"        {\n"
1463e5c31af7Sopenharmony_ci		"            result[texel_index] = 1;\n"
1464e5c31af7Sopenharmony_ci		"        }\n"
1465e5c31af7Sopenharmony_ci		"    }\n"
1466e5c31af7Sopenharmony_ci		"}\n";
1467e5c31af7Sopenharmony_ci
1468e5c31af7Sopenharmony_ci	m_po = SparseBufferTestUtilities::createComputeProgram(m_gl, &cs_body, 1); /* n_cs_body_parts */
1469e5c31af7Sopenharmony_ci
1470e5c31af7Sopenharmony_ci	/* Set up a data buffer we will use to initialize the SSBO with default data.
1471e5c31af7Sopenharmony_ci	 *
1472e5c31af7Sopenharmony_ci	 * CS uses a std140 layout for the SSBO, so we need to add the additional padding.
1473e5c31af7Sopenharmony_ci	 */
1474e5c31af7Sopenharmony_ci	m_ssbo_zero_data_size = static_cast<unsigned int>(4 * sizeof(int) * m_to_width);
1475e5c31af7Sopenharmony_ci	m_ssbo_zero_data	  = new unsigned char[m_ssbo_zero_data_size];
1476e5c31af7Sopenharmony_ci
1477e5c31af7Sopenharmony_ci	memset(m_ssbo_zero_data, 0, m_ssbo_zero_data_size);
1478e5c31af7Sopenharmony_ci
1479e5c31af7Sopenharmony_ci	/* Set up the SSBO */
1480e5c31af7Sopenharmony_ci	m_gl.genBuffers(1, &m_ssbo);
1481e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
1482e5c31af7Sopenharmony_ci
1483e5c31af7Sopenharmony_ci	m_gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, m_ssbo);
1484e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
1485e5c31af7Sopenharmony_ci
1486e5c31af7Sopenharmony_ci	m_gl.bufferData(GL_SHADER_STORAGE_BUFFER, m_ssbo_zero_data_size, m_ssbo_zero_data, GL_STATIC_DRAW);
1487e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferData() call failed.");
1488e5c31af7Sopenharmony_ci
1489e5c31af7Sopenharmony_ci	/* During execution, we will need to use a helper buffer object. The BO will hold
1490e5c31af7Sopenharmony_ci	 * data we will be copying into the sparse buffer object for each iteration.
1491e5c31af7Sopenharmony_ci	 *
1492e5c31af7Sopenharmony_ci	 * Create an array to hold the helper buffer's data and fill it with info that
1493e5c31af7Sopenharmony_ci	 * the compute shader is going to be expecting */
1494e5c31af7Sopenharmony_ci	unsigned char* helper_bo_data_traveller_ptr = NULL;
1495e5c31af7Sopenharmony_ci
1496e5c31af7Sopenharmony_ci	m_helper_bo_data_size = m_to_width * 4; /* rgba */
1497e5c31af7Sopenharmony_ci	m_helper_bo_data	  = new unsigned char[m_helper_bo_data_size];
1498e5c31af7Sopenharmony_ci
1499e5c31af7Sopenharmony_ci	helper_bo_data_traveller_ptr = m_helper_bo_data;
1500e5c31af7Sopenharmony_ci
1501e5c31af7Sopenharmony_ci	for (unsigned int n_texel = 0; n_texel < m_to_width; ++n_texel)
1502e5c31af7Sopenharmony_ci	{
1503e5c31af7Sopenharmony_ci		/* Red */
1504e5c31af7Sopenharmony_ci		*helper_bo_data_traveller_ptr = static_cast<unsigned char>(n_texel % 255);
1505e5c31af7Sopenharmony_ci		++helper_bo_data_traveller_ptr;
1506e5c31af7Sopenharmony_ci
1507e5c31af7Sopenharmony_ci		/* Green */
1508e5c31af7Sopenharmony_ci		*helper_bo_data_traveller_ptr = static_cast<unsigned char>((n_texel + 35) % 255);
1509e5c31af7Sopenharmony_ci		++helper_bo_data_traveller_ptr;
1510e5c31af7Sopenharmony_ci
1511e5c31af7Sopenharmony_ci		/* Blue */
1512e5c31af7Sopenharmony_ci		*helper_bo_data_traveller_ptr = static_cast<unsigned char>((n_texel + 78) % 255);
1513e5c31af7Sopenharmony_ci		++helper_bo_data_traveller_ptr;
1514e5c31af7Sopenharmony_ci
1515e5c31af7Sopenharmony_ci		/* Alpha */
1516e5c31af7Sopenharmony_ci		*helper_bo_data_traveller_ptr = static_cast<unsigned char>((n_texel + 131) % 255);
1517e5c31af7Sopenharmony_ci		++helper_bo_data_traveller_ptr;
1518e5c31af7Sopenharmony_ci	} /* for (all texels to be accessible via the buffer texture) */
1519e5c31af7Sopenharmony_ci
1520e5c31af7Sopenharmony_ci	/* Set up the helper buffer object which we are going to use to copy data into
1521e5c31af7Sopenharmony_ci	 * the sparse buffer object. */
1522e5c31af7Sopenharmony_ci	m_gl.genBuffers(1, &m_helper_bo);
1523e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
1524e5c31af7Sopenharmony_ci
1525e5c31af7Sopenharmony_ci	m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
1526e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
1527e5c31af7Sopenharmony_ci
1528e5c31af7Sopenharmony_ci	m_gl.bufferData(GL_COPY_READ_BUFFER, m_helper_bo_data_size, m_helper_bo_data, GL_STATIC_DRAW);
1529e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferData() call failed.");
1530e5c31af7Sopenharmony_ci
1531e5c31af7Sopenharmony_ci	/* Set up the texture buffer object. We will attach the actual buffer storage
1532e5c31af7Sopenharmony_ci	 * in execute() */
1533e5c31af7Sopenharmony_ci	m_gl.genTextures(1, &m_to);
1534e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenTextures() call failed.");
1535e5c31af7Sopenharmony_ci
1536e5c31af7Sopenharmony_ci	m_gl.bindTexture(GL_TEXTURE_BUFFER, m_to);
1537e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindTexture() call failed.");
1538e5c31af7Sopenharmony_ci
1539e5c31af7Sopenharmony_ci	/* Determine the number of bytes both the helper and the sparse buffer
1540e5c31af7Sopenharmony_ci	 * object need to be able to hold, at maximum */
1541e5c31af7Sopenharmony_ci	m_sparse_bo_size		 = static_cast<unsigned int>(m_to_width * sizeof(int));
1542e5c31af7Sopenharmony_ci	m_sparse_bo_size_rounded = SparseBufferTestUtilities::alignOffset(m_sparse_bo_size, m_page_size);
1543e5c31af7Sopenharmony_ci
1544e5c31af7Sopenharmony_ci	return true;
1545e5c31af7Sopenharmony_ci}
1546e5c31af7Sopenharmony_ci
1547e5c31af7Sopenharmony_ci/** Initializes GL objects which are needed for a single test case iteration.
1548e5c31af7Sopenharmony_ci *
1549e5c31af7Sopenharmony_ci *  deinitTestCaseIteration() will be called after the test case is executed in ::execute()
1550e5c31af7Sopenharmony_ci *  to release these objects.
1551e5c31af7Sopenharmony_ci **/
1552e5c31af7Sopenharmony_cibool BufferTextureStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo)
1553e5c31af7Sopenharmony_ci{
1554e5c31af7Sopenharmony_ci	bool result = true;
1555e5c31af7Sopenharmony_ci
1556e5c31af7Sopenharmony_ci	/* Cache the BO id, if not cached already */
1557e5c31af7Sopenharmony_ci	DE_ASSERT(m_sparse_bo == 0 || m_sparse_bo == sparse_bo);
1558e5c31af7Sopenharmony_ci
1559e5c31af7Sopenharmony_ci	m_sparse_bo = sparse_bo;
1560e5c31af7Sopenharmony_ci
1561e5c31af7Sopenharmony_ci	return result;
1562e5c31af7Sopenharmony_ci}
1563e5c31af7Sopenharmony_ci
1564e5c31af7Sopenharmony_ci/** Constructor.
1565e5c31af7Sopenharmony_ci *
1566e5c31af7Sopenharmony_ci *  @param gl                         GL entry-points container
1567e5c31af7Sopenharmony_ci *  @param testContext                CTS test context
1568e5c31af7Sopenharmony_ci *  @param page_size                  Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query.
1569e5c31af7Sopenharmony_ci *  @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point.
1570e5c31af7Sopenharmony_ci */
1571e5c31af7Sopenharmony_ciClearOpsBufferStorageTestCase::ClearOpsBufferStorageTestCase(const glw::Functions& gl, tcu::TestContext& testContext,
1572e5c31af7Sopenharmony_ci															 glw::GLint page_size)
1573e5c31af7Sopenharmony_ci	: m_gl(gl)
1574e5c31af7Sopenharmony_ci	, m_helper_bo(0)
1575e5c31af7Sopenharmony_ci	, m_initial_data(DE_NULL)
1576e5c31af7Sopenharmony_ci	, m_n_pages_to_use(16)
1577e5c31af7Sopenharmony_ci	, m_page_size(page_size)
1578e5c31af7Sopenharmony_ci	, m_sparse_bo(0)
1579e5c31af7Sopenharmony_ci	, m_sparse_bo_size_rounded(0)
1580e5c31af7Sopenharmony_ci	, m_testCtx(testContext)
1581e5c31af7Sopenharmony_ci{
1582e5c31af7Sopenharmony_ci	/* Left blank intentionally */
1583e5c31af7Sopenharmony_ci}
1584e5c31af7Sopenharmony_ci
1585e5c31af7Sopenharmony_ci/** Releases all GL objects used across all test case iterations.
1586e5c31af7Sopenharmony_ci *
1587e5c31af7Sopenharmony_ci *  Called once during BufferStorage test run-time.
1588e5c31af7Sopenharmony_ci */
1589e5c31af7Sopenharmony_civoid ClearOpsBufferStorageTestCase::deinitTestCaseGlobal()
1590e5c31af7Sopenharmony_ci{
1591e5c31af7Sopenharmony_ci	if (m_helper_bo != 0)
1592e5c31af7Sopenharmony_ci	{
1593e5c31af7Sopenharmony_ci		m_gl.deleteBuffers(1, &m_helper_bo);
1594e5c31af7Sopenharmony_ci
1595e5c31af7Sopenharmony_ci		m_helper_bo = 0;
1596e5c31af7Sopenharmony_ci	}
1597e5c31af7Sopenharmony_ci
1598e5c31af7Sopenharmony_ci	if (m_initial_data != DE_NULL)
1599e5c31af7Sopenharmony_ci	{
1600e5c31af7Sopenharmony_ci		delete[] m_initial_data;
1601e5c31af7Sopenharmony_ci
1602e5c31af7Sopenharmony_ci		m_initial_data = DE_NULL;
1603e5c31af7Sopenharmony_ci	}
1604e5c31af7Sopenharmony_ci}
1605e5c31af7Sopenharmony_ci
1606e5c31af7Sopenharmony_ci/** Releases temporary GL objects, created specifically for one test case iteration. */
1607e5c31af7Sopenharmony_civoid ClearOpsBufferStorageTestCase::deinitTestCaseIteration()
1608e5c31af7Sopenharmony_ci{
1609e5c31af7Sopenharmony_ci	if (m_sparse_bo != 0)
1610e5c31af7Sopenharmony_ci	{
1611e5c31af7Sopenharmony_ci		m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
1612e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
1613e5c31af7Sopenharmony_ci
1614e5c31af7Sopenharmony_ci		m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,				  /* offset */
1615e5c31af7Sopenharmony_ci									 m_sparse_bo_size_rounded, GL_FALSE); /* commit */
1616e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
1617e5c31af7Sopenharmony_ci
1618e5c31af7Sopenharmony_ci		m_sparse_bo = 0;
1619e5c31af7Sopenharmony_ci	}
1620e5c31af7Sopenharmony_ci}
1621e5c31af7Sopenharmony_ci
1622e5c31af7Sopenharmony_ci/** Executes a single test iteration. The BufferStorage test will call this method
1623e5c31af7Sopenharmony_ci *  numerously during its life-time, testing various valid flag combinations applied
1624e5c31af7Sopenharmony_ci *  to the tested sparse buffer object at glBufferStorage() call time.
1625e5c31af7Sopenharmony_ci *
1626e5c31af7Sopenharmony_ci *  @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage()
1627e5c31af7Sopenharmony_ci *                                 call to set up the sparse buffer's storage.
1628e5c31af7Sopenharmony_ci *
1629e5c31af7Sopenharmony_ci *  @return true if the test case executed correctly, false otherwise.
1630e5c31af7Sopenharmony_ci */
1631e5c31af7Sopenharmony_cibool ClearOpsBufferStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags)
1632e5c31af7Sopenharmony_ci{
1633e5c31af7Sopenharmony_ci	(void)sparse_bo_storage_flags;
1634e5c31af7Sopenharmony_ci	bool			   result	 = true;
1635e5c31af7Sopenharmony_ci	const unsigned int data_rgba8 = 0x12345678;
1636e5c31af7Sopenharmony_ci
1637e5c31af7Sopenharmony_ci	for (unsigned int n_clear_op_type = 0; n_clear_op_type < 2; /* glClearBufferData(), glClearBufferSubData() */
1638e5c31af7Sopenharmony_ci		 ++n_clear_op_type)
1639e5c31af7Sopenharmony_ci	{
1640e5c31af7Sopenharmony_ci		const bool use_clear_buffer_data_call = (n_clear_op_type == 0);
1641e5c31af7Sopenharmony_ci
1642e5c31af7Sopenharmony_ci		/* We will run the test case in two iterations:
1643e5c31af7Sopenharmony_ci		 *
1644e5c31af7Sopenharmony_ci		 * 1) All pages will have a physical backing.
1645e5c31af7Sopenharmony_ci		 * 2) Half of the pages will have a physical backing.
1646e5c31af7Sopenharmony_ci		 */
1647e5c31af7Sopenharmony_ci		for (unsigned int n_iteration = 0; n_iteration < 2; ++n_iteration)
1648e5c31af7Sopenharmony_ci		{
1649e5c31af7Sopenharmony_ci			/* By default, for each iteration all sparse buffer pages are commited.
1650e5c31af7Sopenharmony_ci			 *
1651e5c31af7Sopenharmony_ci			 * For the last iteration, we need to de-commit the latter half before
1652e5c31af7Sopenharmony_ci			 * proceeding with the test.
1653e5c31af7Sopenharmony_ci			 */
1654e5c31af7Sopenharmony_ci			const bool all_pages_committed = (n_iteration == 0);
1655e5c31af7Sopenharmony_ci
1656e5c31af7Sopenharmony_ci			if (!all_pages_committed)
1657e5c31af7Sopenharmony_ci			{
1658e5c31af7Sopenharmony_ci				m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
1659e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
1660e5c31af7Sopenharmony_ci
1661e5c31af7Sopenharmony_ci				m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, m_sparse_bo_size_rounded / 2, /* offset */
1662e5c31af7Sopenharmony_ci											 m_sparse_bo_size_rounded / 2,					/* size   */
1663e5c31af7Sopenharmony_ci											 GL_TRUE);										/* commit */
1664e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
1665e5c31af7Sopenharmony_ci			}
1666e5c31af7Sopenharmony_ci
1667e5c31af7Sopenharmony_ci			/* Set up the sparse buffer contents */
1668e5c31af7Sopenharmony_ci			m_gl.bindBuffer(GL_ARRAY_BUFFER, m_helper_bo);
1669e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
1670e5c31af7Sopenharmony_ci
1671e5c31af7Sopenharmony_ci			m_gl.bufferSubData(GL_ARRAY_BUFFER, 0, /* offset */
1672e5c31af7Sopenharmony_ci							   m_sparse_bo_size_rounded, m_initial_data);
1673e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferSubData() call failed.");
1674e5c31af7Sopenharmony_ci
1675e5c31af7Sopenharmony_ci			m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
1676e5c31af7Sopenharmony_ci			m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_sparse_bo);
1677e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call(s) failed.");
1678e5c31af7Sopenharmony_ci
1679e5c31af7Sopenharmony_ci			m_gl.copyBufferSubData(GL_COPY_READ_BUFFER,  /* readTarget  */
1680e5c31af7Sopenharmony_ci								   GL_COPY_WRITE_BUFFER, /* writeTarget */
1681e5c31af7Sopenharmony_ci								   0,					 /* readOffset */
1682e5c31af7Sopenharmony_ci								   0,					 /* writeOffset */
1683e5c31af7Sopenharmony_ci								   m_sparse_bo_size_rounded);
1684e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
1685e5c31af7Sopenharmony_ci
1686e5c31af7Sopenharmony_ci			/* Issue the clear call */
1687e5c31af7Sopenharmony_ci			unsigned int clear_region_size		   = 0;
1688e5c31af7Sopenharmony_ci			unsigned int clear_region_start_offset = 0;
1689e5c31af7Sopenharmony_ci
1690e5c31af7Sopenharmony_ci			if (use_clear_buffer_data_call)
1691e5c31af7Sopenharmony_ci			{
1692e5c31af7Sopenharmony_ci				DE_ASSERT((m_sparse_bo_size_rounded % sizeof(unsigned int)) == 0);
1693e5c31af7Sopenharmony_ci
1694e5c31af7Sopenharmony_ci				clear_region_size		  = m_sparse_bo_size_rounded;
1695e5c31af7Sopenharmony_ci				clear_region_start_offset = 0;
1696e5c31af7Sopenharmony_ci
1697e5c31af7Sopenharmony_ci				m_gl.clearBufferData(GL_COPY_WRITE_BUFFER, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, &data_rgba8);
1698e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glClearBufferData() call failed.");
1699e5c31af7Sopenharmony_ci			}
1700e5c31af7Sopenharmony_ci			else
1701e5c31af7Sopenharmony_ci			{
1702e5c31af7Sopenharmony_ci				DE_ASSERT(((m_sparse_bo_size_rounded / 2) % sizeof(unsigned int)) == 0);
1703e5c31af7Sopenharmony_ci				DE_ASSERT(((m_sparse_bo_size_rounded) % sizeof(unsigned int)) == 0);
1704e5c31af7Sopenharmony_ci
1705e5c31af7Sopenharmony_ci				clear_region_size		  = m_sparse_bo_size_rounded / 2;
1706e5c31af7Sopenharmony_ci				clear_region_start_offset = m_sparse_bo_size_rounded / 2;
1707e5c31af7Sopenharmony_ci
1708e5c31af7Sopenharmony_ci				m_gl.clearBufferSubData(GL_COPY_WRITE_BUFFER, GL_RGBA8, clear_region_start_offset, clear_region_size,
1709e5c31af7Sopenharmony_ci										GL_RGBA, GL_UNSIGNED_BYTE, &data_rgba8);
1710e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glClearBufferSubData() call failed.");
1711e5c31af7Sopenharmony_ci			}
1712e5c31af7Sopenharmony_ci
1713e5c31af7Sopenharmony_ci			/* Retrieve the modified buffer's contents */
1714e5c31af7Sopenharmony_ci			const unsigned char* result_data = NULL;
1715e5c31af7Sopenharmony_ci
1716e5c31af7Sopenharmony_ci			m_gl.copyBufferSubData(GL_COPY_WRITE_BUFFER, /* readTarget  */
1717e5c31af7Sopenharmony_ci								   GL_COPY_READ_BUFFER,  /* writeTarget */
1718e5c31af7Sopenharmony_ci								   0,					 /* readOffset  */
1719e5c31af7Sopenharmony_ci								   0,					 /* writeOffset */
1720e5c31af7Sopenharmony_ci								   m_sparse_bo_size_rounded);
1721e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
1722e5c31af7Sopenharmony_ci
1723e5c31af7Sopenharmony_ci			result_data = (unsigned char*)m_gl.mapBufferRange(GL_COPY_READ_BUFFER, 0, /* offset */
1724e5c31af7Sopenharmony_ci															  m_sparse_bo_size_rounded, GL_MAP_READ_BIT);
1725e5c31af7Sopenharmony_ci
1726e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMapBufferRange() call failed.");
1727e5c31af7Sopenharmony_ci
1728e5c31af7Sopenharmony_ci			/* Verify the result data: unmodified region */
1729e5c31af7Sopenharmony_ci			bool			   result_local			  = true;
1730e5c31af7Sopenharmony_ci			const unsigned int unmodified_region_size = (use_clear_buffer_data_call) ? 0 : clear_region_start_offset;
1731e5c31af7Sopenharmony_ci			const unsigned int unmodified_region_start_offset = 0;
1732e5c31af7Sopenharmony_ci
1733e5c31af7Sopenharmony_ci			for (unsigned int n_current_byte = unmodified_region_start_offset;
1734e5c31af7Sopenharmony_ci				 (n_current_byte < unmodified_region_start_offset + unmodified_region_size) && result_local;
1735e5c31af7Sopenharmony_ci				 ++n_current_byte)
1736e5c31af7Sopenharmony_ci			{
1737e5c31af7Sopenharmony_ci				const unsigned int  current_initial_data_offset = n_current_byte - unmodified_region_start_offset;
1738e5c31af7Sopenharmony_ci				const unsigned char expected_value				= m_initial_data[current_initial_data_offset];
1739e5c31af7Sopenharmony_ci				const unsigned char found_value					= result_data[n_current_byte];
1740e5c31af7Sopenharmony_ci
1741e5c31af7Sopenharmony_ci				if (expected_value != found_value)
1742e5c31af7Sopenharmony_ci				{
1743e5c31af7Sopenharmony_ci					m_testCtx.getLog() << tcu::TestLog::Message
1744e5c31af7Sopenharmony_ci									   << "Unmodified buffer object region has invalid contents. Expected byte "
1745e5c31af7Sopenharmony_ci									   << "[" << (int)expected_value << "]"
1746e5c31af7Sopenharmony_ci																		", found byte:"
1747e5c31af7Sopenharmony_ci																		"["
1748e5c31af7Sopenharmony_ci									   << (int)found_value << "]"
1749e5c31af7Sopenharmony_ci															  " at index "
1750e5c31af7Sopenharmony_ci															  "["
1751e5c31af7Sopenharmony_ci									   << n_current_byte << "]; "
1752e5c31af7Sopenharmony_ci															"call type:"
1753e5c31af7Sopenharmony_ci															"["
1754e5c31af7Sopenharmony_ci									   << ((use_clear_buffer_data_call) ? "glClearBufferData()" :
1755e5c31af7Sopenharmony_ci																		  "glClearBufferSubData()")
1756e5c31af7Sopenharmony_ci									   << "]"
1757e5c31af7Sopenharmony_ci										  ", all required pages committed?:"
1758e5c31af7Sopenharmony_ci										  "["
1759e5c31af7Sopenharmony_ci									   << ((all_pages_committed) ? "yes" : "no") << "]" << tcu::TestLog::EndMessage;
1760e5c31af7Sopenharmony_ci
1761e5c31af7Sopenharmony_ci					result_local = false;
1762e5c31af7Sopenharmony_ci					break;
1763e5c31af7Sopenharmony_ci				}
1764e5c31af7Sopenharmony_ci			}
1765e5c31af7Sopenharmony_ci
1766e5c31af7Sopenharmony_ci			result &= result_local;
1767e5c31af7Sopenharmony_ci			result_local = true;
1768e5c31af7Sopenharmony_ci
1769e5c31af7Sopenharmony_ci			/* Verify the result data: modified region (clamped to the memory region
1770e5c31af7Sopenharmony_ci			 * with actual physical backing) */
1771e5c31af7Sopenharmony_ci			const unsigned int modified_region_size			= (all_pages_committed) ? clear_region_size : 0;
1772e5c31af7Sopenharmony_ci			const unsigned int modified_region_start_offset = clear_region_start_offset;
1773e5c31af7Sopenharmony_ci
1774e5c31af7Sopenharmony_ci			for (unsigned int n_current_byte = modified_region_start_offset;
1775e5c31af7Sopenharmony_ci				 (n_current_byte < modified_region_start_offset + modified_region_size) && result_local;
1776e5c31af7Sopenharmony_ci				 ++n_current_byte)
1777e5c31af7Sopenharmony_ci			{
1778e5c31af7Sopenharmony_ci				const unsigned char component_offset = n_current_byte % 4;
1779e5c31af7Sopenharmony_ci				const unsigned char expected_value =
1780e5c31af7Sopenharmony_ci					static_cast<unsigned char>((data_rgba8 & (0xFFu << (component_offset * 8))) >> (component_offset * 8));
1781e5c31af7Sopenharmony_ci				const unsigned char found_value = result_data[n_current_byte];
1782e5c31af7Sopenharmony_ci
1783e5c31af7Sopenharmony_ci				if (expected_value != found_value)
1784e5c31af7Sopenharmony_ci				{
1785e5c31af7Sopenharmony_ci					m_testCtx.getLog() << tcu::TestLog::Message
1786e5c31af7Sopenharmony_ci									   << "Modified buffer object region has invalid contents. Expected byte "
1787e5c31af7Sopenharmony_ci									   << "[" << (int)expected_value << "]"
1788e5c31af7Sopenharmony_ci																		", found byte:"
1789e5c31af7Sopenharmony_ci																		"["
1790e5c31af7Sopenharmony_ci									   << (int)found_value << "]"
1791e5c31af7Sopenharmony_ci															  " at index "
1792e5c31af7Sopenharmony_ci															  "["
1793e5c31af7Sopenharmony_ci									   << n_current_byte << "]; "
1794e5c31af7Sopenharmony_ci															"call type:"
1795e5c31af7Sopenharmony_ci															"["
1796e5c31af7Sopenharmony_ci									   << ((use_clear_buffer_data_call) ? "glClearBufferData()" :
1797e5c31af7Sopenharmony_ci																		  "glClearBufferSubData()")
1798e5c31af7Sopenharmony_ci									   << "]"
1799e5c31af7Sopenharmony_ci										  ", all required pages committed?:"
1800e5c31af7Sopenharmony_ci										  "["
1801e5c31af7Sopenharmony_ci									   << ((all_pages_committed) ? "yes" : "no") << "]" << tcu::TestLog::EndMessage;
1802e5c31af7Sopenharmony_ci
1803e5c31af7Sopenharmony_ci					result_local = false;
1804e5c31af7Sopenharmony_ci					break;
1805e5c31af7Sopenharmony_ci				}
1806e5c31af7Sopenharmony_ci			}
1807e5c31af7Sopenharmony_ci
1808e5c31af7Sopenharmony_ci			result &= result_local;
1809e5c31af7Sopenharmony_ci
1810e5c31af7Sopenharmony_ci			/* Unmap the storage before proceeding */
1811e5c31af7Sopenharmony_ci			m_gl.unmapBuffer(GL_COPY_READ_BUFFER);
1812e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUnmapBuffer() call failed.");
1813e5c31af7Sopenharmony_ci		} /* for (both iterations) */
1814e5c31af7Sopenharmony_ci	}	 /* for (both clear types) */
1815e5c31af7Sopenharmony_ci
1816e5c31af7Sopenharmony_ci	return result;
1817e5c31af7Sopenharmony_ci}
1818e5c31af7Sopenharmony_ci
1819e5c31af7Sopenharmony_ci/** Initializes GL objects used across all test case iterations.
1820e5c31af7Sopenharmony_ci *
1821e5c31af7Sopenharmony_ci *  Called once during BufferStorage test run-time.
1822e5c31af7Sopenharmony_ci */
1823e5c31af7Sopenharmony_cibool ClearOpsBufferStorageTestCase::initTestCaseGlobal()
1824e5c31af7Sopenharmony_ci{
1825e5c31af7Sopenharmony_ci	unsigned int	   n_bytes_filled = 0;
1826e5c31af7Sopenharmony_ci	const unsigned int n_bytes_needed = m_n_pages_to_use * m_page_size;
1827e5c31af7Sopenharmony_ci
1828e5c31af7Sopenharmony_ci	/* Determine the number of bytes both the helper and the sparse buffer
1829e5c31af7Sopenharmony_ci	 * object need to be able to hold, at maximum */
1830e5c31af7Sopenharmony_ci	m_sparse_bo_size_rounded = SparseBufferTestUtilities::alignOffset(n_bytes_needed, m_page_size);
1831e5c31af7Sopenharmony_ci
1832e5c31af7Sopenharmony_ci	/* Set up the helper BO */
1833e5c31af7Sopenharmony_ci	DE_ASSERT(m_helper_bo == 0);
1834e5c31af7Sopenharmony_ci
1835e5c31af7Sopenharmony_ci	m_gl.genBuffers(1, &m_helper_bo);
1836e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
1837e5c31af7Sopenharmony_ci
1838e5c31af7Sopenharmony_ci	m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
1839e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
1840e5c31af7Sopenharmony_ci
1841e5c31af7Sopenharmony_ci	m_gl.bufferStorage(GL_COPY_READ_BUFFER, m_sparse_bo_size_rounded, DE_NULL,
1842e5c31af7Sopenharmony_ci					   GL_DYNAMIC_STORAGE_BIT | GL_MAP_READ_BIT); /* flags */
1843e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed.");
1844e5c31af7Sopenharmony_ci
1845e5c31af7Sopenharmony_ci	/* Set up a client-side data buffer we will use to fill the sparse BO with data,
1846e5c31af7Sopenharmony_ci	 * to be later cleared with the clear ops */
1847e5c31af7Sopenharmony_ci	DE_ASSERT(m_initial_data == DE_NULL);
1848e5c31af7Sopenharmony_ci
1849e5c31af7Sopenharmony_ci	m_initial_data = new unsigned char[m_sparse_bo_size_rounded];
1850e5c31af7Sopenharmony_ci
1851e5c31af7Sopenharmony_ci	while (n_bytes_filled < m_sparse_bo_size_rounded)
1852e5c31af7Sopenharmony_ci	{
1853e5c31af7Sopenharmony_ci		m_initial_data[n_bytes_filled] = static_cast<unsigned char>(n_bytes_filled % 256);
1854e5c31af7Sopenharmony_ci
1855e5c31af7Sopenharmony_ci		++n_bytes_filled;
1856e5c31af7Sopenharmony_ci	}
1857e5c31af7Sopenharmony_ci
1858e5c31af7Sopenharmony_ci	return true;
1859e5c31af7Sopenharmony_ci}
1860e5c31af7Sopenharmony_ci
1861e5c31af7Sopenharmony_ci/** Initializes GL objects which are needed for a single test case iteration.
1862e5c31af7Sopenharmony_ci *
1863e5c31af7Sopenharmony_ci *  deinitTestCaseIteration() will be called after the test case is executed in ::execute()
1864e5c31af7Sopenharmony_ci *  to release these objects.
1865e5c31af7Sopenharmony_ci **/
1866e5c31af7Sopenharmony_cibool ClearOpsBufferStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo)
1867e5c31af7Sopenharmony_ci{
1868e5c31af7Sopenharmony_ci	bool result = true;
1869e5c31af7Sopenharmony_ci
1870e5c31af7Sopenharmony_ci	/* Cache the BO id, if not cached already */
1871e5c31af7Sopenharmony_ci	DE_ASSERT(m_sparse_bo == 0 || m_sparse_bo == sparse_bo);
1872e5c31af7Sopenharmony_ci
1873e5c31af7Sopenharmony_ci	m_sparse_bo = sparse_bo;
1874e5c31af7Sopenharmony_ci
1875e5c31af7Sopenharmony_ci	/* Set up the sparse bufffer. */
1876e5c31af7Sopenharmony_ci	m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
1877e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
1878e5c31af7Sopenharmony_ci
1879e5c31af7Sopenharmony_ci	m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,				 /* offset */
1880e5c31af7Sopenharmony_ci								 m_sparse_bo_size_rounded, GL_TRUE); /* commit */
1881e5c31af7Sopenharmony_ci
1882e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
1883e5c31af7Sopenharmony_ci
1884e5c31af7Sopenharmony_ci	return result;
1885e5c31af7Sopenharmony_ci}
1886e5c31af7Sopenharmony_ci
1887e5c31af7Sopenharmony_ci/** Constructor.
1888e5c31af7Sopenharmony_ci *
1889e5c31af7Sopenharmony_ci *  @param gl                         GL entry-points container
1890e5c31af7Sopenharmony_ci *  @param testContext                CTS test context
1891e5c31af7Sopenharmony_ci *  @param page_size                  Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query.
1892e5c31af7Sopenharmony_ci *  @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point.
1893e5c31af7Sopenharmony_ci */
1894e5c31af7Sopenharmony_ciCopyOpsBufferStorageTestCase::CopyOpsBufferStorageTestCase(const glw::Functions& gl, tcu::TestContext& testContext,
1895e5c31af7Sopenharmony_ci														   glw::GLint page_size)
1896e5c31af7Sopenharmony_ci	: m_gl(gl)
1897e5c31af7Sopenharmony_ci	, m_helper_bo(0)
1898e5c31af7Sopenharmony_ci	, m_immutable_bo(0)
1899e5c31af7Sopenharmony_ci	, m_page_size(page_size)
1900e5c31af7Sopenharmony_ci	, m_sparse_bo_size(0)
1901e5c31af7Sopenharmony_ci	, m_sparse_bo_size_rounded(0)
1902e5c31af7Sopenharmony_ci	, m_testCtx(testContext)
1903e5c31af7Sopenharmony_ci{
1904e5c31af7Sopenharmony_ci	m_ref_data[0]   = DE_NULL;
1905e5c31af7Sopenharmony_ci	m_ref_data[1]   = DE_NULL;
1906e5c31af7Sopenharmony_ci	m_ref_data[2]   = DE_NULL;
1907e5c31af7Sopenharmony_ci	m_sparse_bos[0] = 0;
1908e5c31af7Sopenharmony_ci	m_sparse_bos[1] = 0;
1909e5c31af7Sopenharmony_ci}
1910e5c31af7Sopenharmony_ci
1911e5c31af7Sopenharmony_ci/** Releases all GL objects used across all test case iterations.
1912e5c31af7Sopenharmony_ci *
1913e5c31af7Sopenharmony_ci *  Called once during BufferStorage test run-time.
1914e5c31af7Sopenharmony_ci */
1915e5c31af7Sopenharmony_ci
1916e5c31af7Sopenharmony_civoid CopyOpsBufferStorageTestCase::deinitTestCaseGlobal()
1917e5c31af7Sopenharmony_ci{
1918e5c31af7Sopenharmony_ci	if (m_helper_bo != 0)
1919e5c31af7Sopenharmony_ci	{
1920e5c31af7Sopenharmony_ci		m_gl.deleteBuffers(1, &m_helper_bo);
1921e5c31af7Sopenharmony_ci
1922e5c31af7Sopenharmony_ci		m_helper_bo = 0;
1923e5c31af7Sopenharmony_ci	}
1924e5c31af7Sopenharmony_ci
1925e5c31af7Sopenharmony_ci	if (m_immutable_bo != 0)
1926e5c31af7Sopenharmony_ci	{
1927e5c31af7Sopenharmony_ci		m_gl.deleteBuffers(1, &m_immutable_bo);
1928e5c31af7Sopenharmony_ci
1929e5c31af7Sopenharmony_ci		m_immutable_bo = 0;
1930e5c31af7Sopenharmony_ci	}
1931e5c31af7Sopenharmony_ci
1932e5c31af7Sopenharmony_ci	for (unsigned int n_ref_data_buffer = 0; n_ref_data_buffer < sizeof(m_ref_data) / sizeof(m_ref_data[0]);
1933e5c31af7Sopenharmony_ci		 ++n_ref_data_buffer)
1934e5c31af7Sopenharmony_ci	{
1935e5c31af7Sopenharmony_ci		if (m_ref_data[n_ref_data_buffer] != DE_NULL)
1936e5c31af7Sopenharmony_ci		{
1937e5c31af7Sopenharmony_ci			delete[] m_ref_data[n_ref_data_buffer];
1938e5c31af7Sopenharmony_ci
1939e5c31af7Sopenharmony_ci			m_ref_data[n_ref_data_buffer] = DE_NULL;
1940e5c31af7Sopenharmony_ci		}
1941e5c31af7Sopenharmony_ci	}
1942e5c31af7Sopenharmony_ci
1943e5c31af7Sopenharmony_ci	/* Only release the test case-owned BO */
1944e5c31af7Sopenharmony_ci	if (m_sparse_bos[1] != 0)
1945e5c31af7Sopenharmony_ci	{
1946e5c31af7Sopenharmony_ci		m_gl.deleteBuffers(1, m_sparse_bos + 1);
1947e5c31af7Sopenharmony_ci
1948e5c31af7Sopenharmony_ci		m_sparse_bos[1] = 0;
1949e5c31af7Sopenharmony_ci	}
1950e5c31af7Sopenharmony_ci}
1951e5c31af7Sopenharmony_ci
1952e5c31af7Sopenharmony_ci/** Releases temporary GL objects, created specifically for one test case iteration. */
1953e5c31af7Sopenharmony_civoid CopyOpsBufferStorageTestCase::deinitTestCaseIteration()
1954e5c31af7Sopenharmony_ci{
1955e5c31af7Sopenharmony_ci	for (unsigned int n_sparse_bo = 0; n_sparse_bo < sizeof(m_sparse_bos) / sizeof(m_sparse_bos[0]); ++n_sparse_bo)
1956e5c31af7Sopenharmony_ci	{
1957e5c31af7Sopenharmony_ci		const glw::GLuint sparse_bo_id = m_sparse_bos[n_sparse_bo];
1958e5c31af7Sopenharmony_ci
1959e5c31af7Sopenharmony_ci		if (sparse_bo_id != 0)
1960e5c31af7Sopenharmony_ci		{
1961e5c31af7Sopenharmony_ci			m_gl.bindBuffer(GL_ARRAY_BUFFER, sparse_bo_id);
1962e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
1963e5c31af7Sopenharmony_ci
1964e5c31af7Sopenharmony_ci			m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,				  /* offset */
1965e5c31af7Sopenharmony_ci										 m_sparse_bo_size_rounded, GL_FALSE); /* commit */
1966e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
1967e5c31af7Sopenharmony_ci		} /* if (sparse_bo_id != 0) */
1968e5c31af7Sopenharmony_ci	}	 /* for (both BOs) */
1969e5c31af7Sopenharmony_ci}
1970e5c31af7Sopenharmony_ci
1971e5c31af7Sopenharmony_ci/** Executes a single test iteration. The BufferStorage test will call this method
1972e5c31af7Sopenharmony_ci *  numerously during its life-time, testing various valid flag combinations applied
1973e5c31af7Sopenharmony_ci *  to the tested sparse buffer object at glBufferStorage() call time.
1974e5c31af7Sopenharmony_ci *
1975e5c31af7Sopenharmony_ci *  @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage()
1976e5c31af7Sopenharmony_ci *                                 call to set up the sparse buffer's storage.
1977e5c31af7Sopenharmony_ci *
1978e5c31af7Sopenharmony_ci *  @return true if the test case executed correctly, false otherwise.
1979e5c31af7Sopenharmony_ci */
1980e5c31af7Sopenharmony_cibool CopyOpsBufferStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags)
1981e5c31af7Sopenharmony_ci{
1982e5c31af7Sopenharmony_ci	(void)sparse_bo_storage_flags;
1983e5c31af7Sopenharmony_ci	bool result = true;
1984e5c31af7Sopenharmony_ci
1985e5c31af7Sopenharmony_ci	/* Iterate over all test cases */
1986e5c31af7Sopenharmony_ci	DE_ASSERT(m_immutable_bo != 0);
1987e5c31af7Sopenharmony_ci	DE_ASSERT(m_sparse_bos[0] != 0);
1988e5c31af7Sopenharmony_ci	DE_ASSERT(m_sparse_bos[1] != 0);
1989e5c31af7Sopenharmony_ci
1990e5c31af7Sopenharmony_ci	for (_test_cases_const_iterator test_iterator = m_test_cases.begin(); test_iterator != m_test_cases.end();
1991e5c31af7Sopenharmony_ci		 ++test_iterator)
1992e5c31af7Sopenharmony_ci	{
1993e5c31af7Sopenharmony_ci		bool			  result_local = true;
1994e5c31af7Sopenharmony_ci		const _test_case& test_case	= *test_iterator;
1995e5c31af7Sopenharmony_ci		const glw::GLuint dst_bo_id =
1996e5c31af7Sopenharmony_ci			test_case.dst_bo_is_sparse ? m_sparse_bos[test_case.dst_bo_sparse_id] : m_immutable_bo;
1997e5c31af7Sopenharmony_ci		const glw::GLuint src_bo_id =
1998e5c31af7Sopenharmony_ci			test_case.src_bo_is_sparse ? m_sparse_bos[test_case.src_bo_sparse_id] : m_immutable_bo;
1999e5c31af7Sopenharmony_ci
2000e5c31af7Sopenharmony_ci		/* Initialize immutable BO data (if used) */
2001e5c31af7Sopenharmony_ci		if (dst_bo_id == m_immutable_bo || src_bo_id == m_immutable_bo)
2002e5c31af7Sopenharmony_ci		{
2003e5c31af7Sopenharmony_ci			m_gl.bindBuffer(GL_ARRAY_BUFFER, m_immutable_bo);
2004e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
2005e5c31af7Sopenharmony_ci
2006e5c31af7Sopenharmony_ci			m_gl.bufferSubData(GL_ARRAY_BUFFER, 0, /* offset */
2007e5c31af7Sopenharmony_ci							   m_sparse_bo_size_rounded, m_ref_data[0]);
2008e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferSubData() call failed.");
2009e5c31af7Sopenharmony_ci		}
2010e5c31af7Sopenharmony_ci
2011e5c31af7Sopenharmony_ci		/* Initialize sparse BO data storage */
2012e5c31af7Sopenharmony_ci		for (unsigned int n_sparse_bo = 0; n_sparse_bo < sizeof(m_sparse_bos) / sizeof(m_sparse_bos[0]); ++n_sparse_bo)
2013e5c31af7Sopenharmony_ci		{
2014e5c31af7Sopenharmony_ci			const bool is_dst_bo = (dst_bo_id == m_sparse_bos[n_sparse_bo]);
2015e5c31af7Sopenharmony_ci			const bool is_src_bo = (src_bo_id == m_sparse_bos[n_sparse_bo]);
2016e5c31af7Sopenharmony_ci
2017e5c31af7Sopenharmony_ci			if (!is_dst_bo && !is_src_bo)
2018e5c31af7Sopenharmony_ci				continue;
2019e5c31af7Sopenharmony_ci
2020e5c31af7Sopenharmony_ci			m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
2021e5c31af7Sopenharmony_ci			m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_sparse_bos[n_sparse_bo]);
2022e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call(s) failed.");
2023e5c31af7Sopenharmony_ci
2024e5c31af7Sopenharmony_ci			if (is_dst_bo)
2025e5c31af7Sopenharmony_ci			{
2026e5c31af7Sopenharmony_ci				m_gl.bufferPageCommitmentARB(GL_COPY_WRITE_BUFFER, test_case.dst_bo_commit_start_offset,
2027e5c31af7Sopenharmony_ci											 test_case.dst_bo_commit_size, GL_TRUE); /* commit */
2028e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
2029e5c31af7Sopenharmony_ci			}
2030e5c31af7Sopenharmony_ci
2031e5c31af7Sopenharmony_ci			if (is_src_bo)
2032e5c31af7Sopenharmony_ci			{
2033e5c31af7Sopenharmony_ci				m_gl.bufferPageCommitmentARB(GL_COPY_WRITE_BUFFER, test_case.src_bo_commit_start_offset,
2034e5c31af7Sopenharmony_ci											 test_case.src_bo_commit_size, GL_TRUE); /* commit */
2035e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
2036e5c31af7Sopenharmony_ci			}
2037e5c31af7Sopenharmony_ci
2038e5c31af7Sopenharmony_ci			m_gl.bufferSubData(GL_COPY_READ_BUFFER, 0, /* offset */
2039e5c31af7Sopenharmony_ci							   m_sparse_bo_size_rounded, m_ref_data[1 + n_sparse_bo]);
2040e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferSubData() call failed.");
2041e5c31af7Sopenharmony_ci
2042e5c31af7Sopenharmony_ci			m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, /* readOffset */
2043e5c31af7Sopenharmony_ci								   0,											 /* writeOffset */
2044e5c31af7Sopenharmony_ci								   m_sparse_bo_size_rounded);
2045e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
2046e5c31af7Sopenharmony_ci		} /* for (both sparse BOs) */
2047e5c31af7Sopenharmony_ci
2048e5c31af7Sopenharmony_ci		/* Set up the bindings */
2049e5c31af7Sopenharmony_ci		m_gl.bindBuffer(GL_COPY_READ_BUFFER, src_bo_id);
2050e5c31af7Sopenharmony_ci		m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, dst_bo_id);
2051e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
2052e5c31af7Sopenharmony_ci
2053e5c31af7Sopenharmony_ci		/* Issue the copy op */
2054e5c31af7Sopenharmony_ci		m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, test_case.src_bo_start_offset,
2055e5c31af7Sopenharmony_ci							   test_case.dst_bo_start_offset, test_case.n_bytes_to_copy);
2056e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
2057e5c31af7Sopenharmony_ci
2058e5c31af7Sopenharmony_ci		/* Retrieve the destination buffer's contents. The BO used for the previous copy op might have
2059e5c31af7Sopenharmony_ci		 * been a sparse BO, so copy its storage to a helper immutable BO */
2060e5c31af7Sopenharmony_ci		const unsigned short* dst_bo_data_ptr = NULL;
2061e5c31af7Sopenharmony_ci
2062e5c31af7Sopenharmony_ci		m_gl.bindBuffer(GL_COPY_READ_BUFFER, dst_bo_id);
2063e5c31af7Sopenharmony_ci		m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_helper_bo);
2064e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
2065e5c31af7Sopenharmony_ci
2066e5c31af7Sopenharmony_ci		m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, /* readOffset */
2067e5c31af7Sopenharmony_ci							   0,											 /* writeOffset */
2068e5c31af7Sopenharmony_ci							   m_sparse_bo_size_rounded);
2069e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
2070e5c31af7Sopenharmony_ci
2071e5c31af7Sopenharmony_ci		dst_bo_data_ptr = (const unsigned short*)m_gl.mapBufferRange(GL_COPY_WRITE_BUFFER, 0, /* offset */
2072e5c31af7Sopenharmony_ci																	 m_sparse_bo_size_rounded, GL_MAP_READ_BIT);
2073e5c31af7Sopenharmony_ci
2074e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMapBufferRange() call failed.");
2075e5c31af7Sopenharmony_ci
2076e5c31af7Sopenharmony_ci		/* Verify the retrieved data:
2077e5c31af7Sopenharmony_ci		 *
2078e5c31af7Sopenharmony_ci		 * 1. Check the bytes which precede the copy op dst offset. These should be equal to
2079e5c31af7Sopenharmony_ci		 *    the destination buffer's reference data within the committed memory region.
2080e5c31af7Sopenharmony_ci		 **/
2081e5c31af7Sopenharmony_ci		if (test_case.dst_bo_start_offset != 0 && test_case.dst_bo_commit_start_offset < test_case.dst_bo_start_offset)
2082e5c31af7Sopenharmony_ci		{
2083e5c31af7Sopenharmony_ci			DE_ASSERT(((test_case.dst_bo_start_offset - test_case.dst_bo_commit_start_offset) % sizeof(short)) == 0);
2084e5c31af7Sopenharmony_ci
2085e5c31af7Sopenharmony_ci			const unsigned int n_valid_values = static_cast<unsigned int>(
2086e5c31af7Sopenharmony_ci				(test_case.dst_bo_start_offset - test_case.dst_bo_commit_start_offset) / sizeof(short));
2087e5c31af7Sopenharmony_ci
2088e5c31af7Sopenharmony_ci			for (unsigned int n_value = 0; n_value < n_valid_values && result_local; ++n_value)
2089e5c31af7Sopenharmony_ci			{
2090e5c31af7Sopenharmony_ci				const int dst_data_offset = static_cast<int>(sizeof(short) * n_value);
2091e5c31af7Sopenharmony_ci
2092e5c31af7Sopenharmony_ci				if (dst_data_offset >= test_case.dst_bo_commit_start_offset &&
2093e5c31af7Sopenharmony_ci					dst_data_offset < test_case.dst_bo_commit_start_offset + test_case.dst_bo_commit_size)
2094e5c31af7Sopenharmony_ci				{
2095e5c31af7Sopenharmony_ci					const unsigned short expected_short_value =
2096e5c31af7Sopenharmony_ci						*(unsigned short*)((unsigned char*)test_case.dst_bo_ref_data + dst_data_offset);
2097e5c31af7Sopenharmony_ci					const unsigned short found_short_value =
2098e5c31af7Sopenharmony_ci						*(unsigned short*)((unsigned char*)dst_bo_data_ptr + dst_data_offset);
2099e5c31af7Sopenharmony_ci
2100e5c31af7Sopenharmony_ci					if (expected_short_value != found_short_value)
2101e5c31af7Sopenharmony_ci					{
2102e5c31af7Sopenharmony_ci						m_testCtx.getLog()
2103e5c31af7Sopenharmony_ci							<< tcu::TestLog::Message << "Malformed data found in the copy op's destination BO, "
2104e5c31af7Sopenharmony_ci														"preceding the region modified by the copy op. "
2105e5c31af7Sopenharmony_ci							<< "Destination BO id:" << dst_bo_id << " ("
2106e5c31af7Sopenharmony_ci							<< ((test_case.dst_bo_is_sparse) ? "sparse buffer)" : "immutable buffer)")
2107e5c31af7Sopenharmony_ci							<< ", commited region: " << test_case.dst_bo_commit_start_offset << ":"
2108e5c31af7Sopenharmony_ci							<< (test_case.dst_bo_commit_start_offset + test_case.dst_bo_commit_size)
2109e5c31af7Sopenharmony_ci							<< ", copy region: " << test_case.dst_bo_start_offset << ":"
2110e5c31af7Sopenharmony_ci							<< (test_case.dst_bo_start_offset + test_case.n_bytes_to_copy)
2111e5c31af7Sopenharmony_ci							<< ". Source BO id:" << src_bo_id << " ("
2112e5c31af7Sopenharmony_ci							<< ((test_case.src_bo_is_sparse) ? "sparse buffer)" : "immutable buffer)")
2113e5c31af7Sopenharmony_ci							<< ", commited region: " << test_case.src_bo_commit_start_offset << ":"
2114e5c31af7Sopenharmony_ci							<< (test_case.src_bo_commit_start_offset + test_case.src_bo_commit_size)
2115e5c31af7Sopenharmony_ci							<< ", copy region: " << test_case.src_bo_start_offset << ":"
2116e5c31af7Sopenharmony_ci							<< (test_case.src_bo_start_offset + test_case.n_bytes_to_copy) << ". Expected value of "
2117e5c31af7Sopenharmony_ci							<< expected_short_value << ", found value of " << found_short_value
2118e5c31af7Sopenharmony_ci							<< " at dst data offset of " << dst_data_offset << "." << tcu::TestLog::EndMessage;
2119e5c31af7Sopenharmony_ci
2120e5c31af7Sopenharmony_ci						result_local = false;
2121e5c31af7Sopenharmony_ci					}
2122e5c31af7Sopenharmony_ci				}
2123e5c31af7Sopenharmony_ci			} /* for (all preceding values which should not have been affected by the copy op) */
2124e5c31af7Sopenharmony_ci		}	 /* if (copy op did not modify the beginning of the destination buffer storage) */
2125e5c31af7Sopenharmony_ci
2126e5c31af7Sopenharmony_ci		/* 2. Check if the data written to the destination buffer object is correct. */
2127e5c31af7Sopenharmony_ci		for (unsigned int n_copied_short_value = 0;
2128e5c31af7Sopenharmony_ci			 n_copied_short_value < test_case.n_bytes_to_copy / sizeof(short) && result_local; ++n_copied_short_value)
2129e5c31af7Sopenharmony_ci		{
2130e5c31af7Sopenharmony_ci			const int src_data_offset =
2131e5c31af7Sopenharmony_ci				static_cast<unsigned int>(test_case.src_bo_start_offset + sizeof(short) * n_copied_short_value);
2132e5c31af7Sopenharmony_ci			const int dst_data_offset =
2133e5c31af7Sopenharmony_ci				static_cast<unsigned int>(test_case.dst_bo_start_offset + sizeof(short) * n_copied_short_value);
2134e5c31af7Sopenharmony_ci
2135e5c31af7Sopenharmony_ci			if (dst_data_offset >= test_case.dst_bo_commit_start_offset &&
2136e5c31af7Sopenharmony_ci				dst_data_offset < test_case.dst_bo_commit_start_offset + test_case.dst_bo_commit_size &&
2137e5c31af7Sopenharmony_ci				src_data_offset >= test_case.src_bo_commit_start_offset &&
2138e5c31af7Sopenharmony_ci				src_data_offset < test_case.src_bo_commit_start_offset + test_case.src_bo_commit_size)
2139e5c31af7Sopenharmony_ci			{
2140e5c31af7Sopenharmony_ci				const unsigned short expected_short_value =
2141e5c31af7Sopenharmony_ci					*(unsigned short*)((unsigned char*)test_case.src_bo_ref_data + src_data_offset);
2142e5c31af7Sopenharmony_ci				const unsigned short found_short_value =
2143e5c31af7Sopenharmony_ci					*(unsigned short*)((unsigned char*)dst_bo_data_ptr + dst_data_offset);
2144e5c31af7Sopenharmony_ci
2145e5c31af7Sopenharmony_ci				if (expected_short_value != found_short_value)
2146e5c31af7Sopenharmony_ci				{
2147e5c31af7Sopenharmony_ci					m_testCtx.getLog() << tcu::TestLog::Message
2148e5c31af7Sopenharmony_ci									   << "Malformed data found in the copy op's destination BO. "
2149e5c31af7Sopenharmony_ci									   << "Destination BO id:" << dst_bo_id << " ("
2150e5c31af7Sopenharmony_ci									   << ((test_case.dst_bo_is_sparse) ? "sparse buffer)" : "immutable buffer)")
2151e5c31af7Sopenharmony_ci									   << ", commited region: " << test_case.dst_bo_commit_start_offset << ":"
2152e5c31af7Sopenharmony_ci									   << (test_case.dst_bo_commit_start_offset + test_case.dst_bo_commit_size)
2153e5c31af7Sopenharmony_ci									   << ", copy region: " << test_case.dst_bo_start_offset << ":"
2154e5c31af7Sopenharmony_ci									   << (test_case.dst_bo_start_offset + test_case.n_bytes_to_copy)
2155e5c31af7Sopenharmony_ci									   << ". Source BO id:" << src_bo_id << " ("
2156e5c31af7Sopenharmony_ci									   << ((test_case.src_bo_is_sparse) ? "sparse buffer)" : "immutable buffer)")
2157e5c31af7Sopenharmony_ci									   << ", commited region: " << test_case.src_bo_commit_start_offset << ":"
2158e5c31af7Sopenharmony_ci									   << (test_case.src_bo_commit_start_offset + test_case.src_bo_commit_size)
2159e5c31af7Sopenharmony_ci									   << ", copy region: " << test_case.src_bo_start_offset << ":"
2160e5c31af7Sopenharmony_ci									   << (test_case.src_bo_start_offset + test_case.n_bytes_to_copy)
2161e5c31af7Sopenharmony_ci									   << ". Expected value of " << expected_short_value << ", found value of "
2162e5c31af7Sopenharmony_ci									   << found_short_value << " at dst data offset of " << dst_data_offset << "."
2163e5c31af7Sopenharmony_ci									   << tcu::TestLog::EndMessage;
2164e5c31af7Sopenharmony_ci
2165e5c31af7Sopenharmony_ci					result_local = false;
2166e5c31af7Sopenharmony_ci				}
2167e5c31af7Sopenharmony_ci			}
2168e5c31af7Sopenharmony_ci		}
2169e5c31af7Sopenharmony_ci
2170e5c31af7Sopenharmony_ci		/* 3. Verify the remaining data in the committed part of the destination buffer object is left intact. */
2171e5c31af7Sopenharmony_ci		const unsigned int commit_region_end_offset =
2172e5c31af7Sopenharmony_ci			test_case.dst_bo_commit_start_offset + test_case.dst_bo_commit_size;
2173e5c31af7Sopenharmony_ci		const unsigned int copy_region_end_offset = test_case.dst_bo_start_offset + test_case.n_bytes_to_copy;
2174e5c31af7Sopenharmony_ci
2175e5c31af7Sopenharmony_ci		if (commit_region_end_offset > copy_region_end_offset)
2176e5c31af7Sopenharmony_ci		{
2177e5c31af7Sopenharmony_ci			DE_ASSERT(((commit_region_end_offset - copy_region_end_offset) % sizeof(short)) == 0);
2178e5c31af7Sopenharmony_ci
2179e5c31af7Sopenharmony_ci			const unsigned int n_valid_values =
2180e5c31af7Sopenharmony_ci				static_cast<unsigned int>((commit_region_end_offset - copy_region_end_offset) / sizeof(short));
2181e5c31af7Sopenharmony_ci
2182e5c31af7Sopenharmony_ci			for (unsigned int n_value = 0; n_value < n_valid_values && result_local; ++n_value)
2183e5c31af7Sopenharmony_ci			{
2184e5c31af7Sopenharmony_ci				const int dst_data_offset = static_cast<int>(copy_region_end_offset + sizeof(short) * n_value);
2185e5c31af7Sopenharmony_ci
2186e5c31af7Sopenharmony_ci				if (dst_data_offset >= test_case.dst_bo_commit_start_offset &&
2187e5c31af7Sopenharmony_ci					dst_data_offset < test_case.dst_bo_commit_start_offset + test_case.dst_bo_commit_size)
2188e5c31af7Sopenharmony_ci				{
2189e5c31af7Sopenharmony_ci					const unsigned short expected_short_value =
2190e5c31af7Sopenharmony_ci						*(unsigned short*)((unsigned char*)test_case.dst_bo_ref_data + dst_data_offset);
2191e5c31af7Sopenharmony_ci					const unsigned short found_short_value =
2192e5c31af7Sopenharmony_ci						*(unsigned short*)((unsigned char*)dst_bo_data_ptr + dst_data_offset);
2193e5c31af7Sopenharmony_ci
2194e5c31af7Sopenharmony_ci					if (expected_short_value != found_short_value)
2195e5c31af7Sopenharmony_ci					{
2196e5c31af7Sopenharmony_ci						m_testCtx.getLog()
2197e5c31af7Sopenharmony_ci							<< tcu::TestLog::Message << "Malformed data found in the copy op's destination BO, "
2198e5c31af7Sopenharmony_ci														"following the region modified by the copy op. "
2199e5c31af7Sopenharmony_ci							<< "Destination BO id:" << dst_bo_id << " ("
2200e5c31af7Sopenharmony_ci							<< ((test_case.dst_bo_is_sparse) ? "sparse buffer)" : "immutable buffer)")
2201e5c31af7Sopenharmony_ci							<< ", commited region: " << test_case.dst_bo_commit_start_offset << ":"
2202e5c31af7Sopenharmony_ci							<< (test_case.dst_bo_commit_start_offset + test_case.dst_bo_commit_size)
2203e5c31af7Sopenharmony_ci							<< ", copy region: " << test_case.dst_bo_start_offset << ":"
2204e5c31af7Sopenharmony_ci							<< (test_case.dst_bo_start_offset + test_case.n_bytes_to_copy)
2205e5c31af7Sopenharmony_ci							<< ". Source BO id:" << src_bo_id << " ("
2206e5c31af7Sopenharmony_ci							<< ((test_case.src_bo_is_sparse) ? "sparse buffer)" : "immutable buffer)")
2207e5c31af7Sopenharmony_ci							<< ", commited region: " << test_case.src_bo_commit_start_offset << ":"
2208e5c31af7Sopenharmony_ci							<< (test_case.src_bo_commit_start_offset + test_case.src_bo_commit_size)
2209e5c31af7Sopenharmony_ci							<< ", copy region: " << test_case.src_bo_start_offset << ":"
2210e5c31af7Sopenharmony_ci							<< (test_case.src_bo_start_offset + test_case.n_bytes_to_copy) << ". Expected value of "
2211e5c31af7Sopenharmony_ci							<< expected_short_value << ", found value of " << found_short_value
2212e5c31af7Sopenharmony_ci							<< " at dst data offset of " << dst_data_offset << "." << tcu::TestLog::EndMessage;
2213e5c31af7Sopenharmony_ci
2214e5c31af7Sopenharmony_ci						result_local = false;
2215e5c31af7Sopenharmony_ci					}
2216e5c31af7Sopenharmony_ci				}
2217e5c31af7Sopenharmony_ci			} /* for (all preceding values which should not have been affected by the copy op) */
2218e5c31af7Sopenharmony_ci		}	 /* if (copy op did not modify the beginning of the destination buffer storage) */
2219e5c31af7Sopenharmony_ci
2220e5c31af7Sopenharmony_ci		/* Unmap the buffer storage */
2221e5c31af7Sopenharmony_ci		m_gl.unmapBuffer(GL_COPY_WRITE_BUFFER);
2222e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUnmapBuffer() call failed.");
2223e5c31af7Sopenharmony_ci
2224e5c31af7Sopenharmony_ci		/* Clean up */
2225e5c31af7Sopenharmony_ci		for (unsigned int n_sparse_bo = 0; n_sparse_bo < sizeof(m_sparse_bos) / sizeof(m_sparse_bos[0]); ++n_sparse_bo)
2226e5c31af7Sopenharmony_ci		{
2227e5c31af7Sopenharmony_ci			const bool is_dst_bo = (dst_bo_id == m_sparse_bos[n_sparse_bo]);
2228e5c31af7Sopenharmony_ci			const bool is_src_bo = (src_bo_id == m_sparse_bos[n_sparse_bo]);
2229e5c31af7Sopenharmony_ci
2230e5c31af7Sopenharmony_ci			if (is_dst_bo || is_src_bo)
2231e5c31af7Sopenharmony_ci			{
2232e5c31af7Sopenharmony_ci				m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bos[n_sparse_bo]);
2233e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
2234e5c31af7Sopenharmony_ci
2235e5c31af7Sopenharmony_ci				m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0, m_sparse_bo_size_rounded, GL_FALSE); /* commit */
2236e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
2237e5c31af7Sopenharmony_ci			}
2238e5c31af7Sopenharmony_ci		}
2239e5c31af7Sopenharmony_ci
2240e5c31af7Sopenharmony_ci		result &= result_local;
2241e5c31af7Sopenharmony_ci	} /* for (all test cases) */
2242e5c31af7Sopenharmony_ci
2243e5c31af7Sopenharmony_ci	return result;
2244e5c31af7Sopenharmony_ci}
2245e5c31af7Sopenharmony_ci
2246e5c31af7Sopenharmony_ci/** Allocates reference buffers, fills them with data and updates the m_ref_data array. */
2247e5c31af7Sopenharmony_civoid CopyOpsBufferStorageTestCase::initReferenceData()
2248e5c31af7Sopenharmony_ci{
2249e5c31af7Sopenharmony_ci	DE_ASSERT(m_sparse_bo_size_rounded != 0);
2250e5c31af7Sopenharmony_ci	DE_ASSERT((m_sparse_bo_size_rounded % 2) == 0);
2251e5c31af7Sopenharmony_ci	DE_ASSERT(sizeof(short) == 2);
2252e5c31af7Sopenharmony_ci
2253e5c31af7Sopenharmony_ci	for (unsigned int n_ref_data_buffer = 0; n_ref_data_buffer < sizeof(m_ref_data) / sizeof(m_ref_data[0]);
2254e5c31af7Sopenharmony_ci		 ++n_ref_data_buffer)
2255e5c31af7Sopenharmony_ci	{
2256e5c31af7Sopenharmony_ci		DE_ASSERT(m_ref_data[n_ref_data_buffer] == DE_NULL);
2257e5c31af7Sopenharmony_ci
2258e5c31af7Sopenharmony_ci		m_ref_data[n_ref_data_buffer] = new unsigned short[m_sparse_bo_size_rounded / 2];
2259e5c31af7Sopenharmony_ci
2260e5c31af7Sopenharmony_ci		/* Write reference values. */
2261e5c31af7Sopenharmony_ci		for (unsigned int n_short_value = 0; n_short_value < m_sparse_bo_size_rounded / 2; ++n_short_value)
2262e5c31af7Sopenharmony_ci		{
2263e5c31af7Sopenharmony_ci			m_ref_data[n_ref_data_buffer][n_short_value] =
2264e5c31af7Sopenharmony_ci				(unsigned short)((n_ref_data_buffer + 1) * (n_short_value + 1));
2265e5c31af7Sopenharmony_ci		}
2266e5c31af7Sopenharmony_ci	} /* for (all reference data buffers) */
2267e5c31af7Sopenharmony_ci}
2268e5c31af7Sopenharmony_ci
2269e5c31af7Sopenharmony_ci/** Initializes GL objects used across all test case iterations.
2270e5c31af7Sopenharmony_ci *
2271e5c31af7Sopenharmony_ci *  Called once during BufferStorage test run-time.
2272e5c31af7Sopenharmony_ci */
2273e5c31af7Sopenharmony_cibool CopyOpsBufferStorageTestCase::initTestCaseGlobal()
2274e5c31af7Sopenharmony_ci{
2275e5c31af7Sopenharmony_ci	m_sparse_bo_size		 = 2 * 3 * 4 * m_page_size;
2276e5c31af7Sopenharmony_ci	m_sparse_bo_size_rounded = SparseBufferTestUtilities::alignOffset(m_sparse_bo_size, m_page_size);
2277e5c31af7Sopenharmony_ci
2278e5c31af7Sopenharmony_ci	initReferenceData();
2279e5c31af7Sopenharmony_ci
2280e5c31af7Sopenharmony_ci	/* Initialize the sparse buffer object */
2281e5c31af7Sopenharmony_ci	m_gl.genBuffers(1, m_sparse_bos + 1);
2282e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
2283e5c31af7Sopenharmony_ci
2284e5c31af7Sopenharmony_ci	m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bos[1]);
2285e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
2286e5c31af7Sopenharmony_ci
2287e5c31af7Sopenharmony_ci	m_gl.bufferStorage(GL_ARRAY_BUFFER, m_sparse_bo_size_rounded, DE_NULL, /* data */
2288e5c31af7Sopenharmony_ci					   GL_SPARSE_STORAGE_BIT_ARB);
2289e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed.");
2290e5c31af7Sopenharmony_ci
2291e5c31af7Sopenharmony_ci	/* Initialize the immutable buffer objects used by the test */
2292e5c31af7Sopenharmony_ci	for (unsigned int n_bo = 0; n_bo < 2; /* helper + immutable BO used for the copy ops */
2293e5c31af7Sopenharmony_ci		 ++n_bo)
2294e5c31af7Sopenharmony_ci	{
2295e5c31af7Sopenharmony_ci		glw::GLuint* bo_id_ptr = (n_bo == 0) ? &m_helper_bo : &m_immutable_bo;
2296e5c31af7Sopenharmony_ci		glw::GLenum  flags	 = GL_DYNAMIC_STORAGE_BIT;
2297e5c31af7Sopenharmony_ci
2298e5c31af7Sopenharmony_ci		if (n_bo == 0)
2299e5c31af7Sopenharmony_ci		{
2300e5c31af7Sopenharmony_ci			flags |= GL_MAP_READ_BIT;
2301e5c31af7Sopenharmony_ci		}
2302e5c31af7Sopenharmony_ci
2303e5c31af7Sopenharmony_ci		/* Initialize the immutable buffer object */
2304e5c31af7Sopenharmony_ci		m_gl.genBuffers(1, bo_id_ptr);
2305e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
2306e5c31af7Sopenharmony_ci
2307e5c31af7Sopenharmony_ci		m_gl.bindBuffer(GL_ARRAY_BUFFER, *bo_id_ptr);
2308e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
2309e5c31af7Sopenharmony_ci
2310e5c31af7Sopenharmony_ci		m_gl.bufferStorage(GL_ARRAY_BUFFER, m_sparse_bo_size_rounded, m_ref_data[0], flags);
2311e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed.");
2312e5c31af7Sopenharmony_ci	}
2313e5c31af7Sopenharmony_ci
2314e5c31af7Sopenharmony_ci	return true;
2315e5c31af7Sopenharmony_ci}
2316e5c31af7Sopenharmony_ci
2317e5c31af7Sopenharmony_ci/** Initializes GL objects which are needed for a single test case iteration.
2318e5c31af7Sopenharmony_ci *
2319e5c31af7Sopenharmony_ci *  deinitTestCaseIteration() will be called after the test case is executed in ::execute()
2320e5c31af7Sopenharmony_ci *  to release these objects.
2321e5c31af7Sopenharmony_ci **/
2322e5c31af7Sopenharmony_cibool CopyOpsBufferStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo)
2323e5c31af7Sopenharmony_ci{
2324e5c31af7Sopenharmony_ci	bool result = true;
2325e5c31af7Sopenharmony_ci
2326e5c31af7Sopenharmony_ci	/* Remember the BO id */
2327e5c31af7Sopenharmony_ci	m_sparse_bos[0] = sparse_bo;
2328e5c31af7Sopenharmony_ci
2329e5c31af7Sopenharmony_ci	/* Initialize test cases, if this is the first call to initTestCaseIteration() */
2330e5c31af7Sopenharmony_ci	if (m_test_cases.size() == 0)
2331e5c31af7Sopenharmony_ci	{
2332e5c31af7Sopenharmony_ci		initTestCases();
2333e5c31af7Sopenharmony_ci	}
2334e5c31af7Sopenharmony_ci
2335e5c31af7Sopenharmony_ci	/* Make sure all pages of the provided sparse BO are de-committed before
2336e5c31af7Sopenharmony_ci	 * ::execute() is called. */
2337e5c31af7Sopenharmony_ci	m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bos[0]);
2338e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
2339e5c31af7Sopenharmony_ci
2340e5c31af7Sopenharmony_ci	m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,				  /* offset */
2341e5c31af7Sopenharmony_ci								 m_sparse_bo_size_rounded, GL_FALSE); /* commit */
2342e5c31af7Sopenharmony_ci
2343e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
2344e5c31af7Sopenharmony_ci
2345e5c31af7Sopenharmony_ci	return result;
2346e5c31af7Sopenharmony_ci}
2347e5c31af7Sopenharmony_ci
2348e5c31af7Sopenharmony_ci/** Fills m_test_cases with test case descriptors. Each such descriptor defines
2349e5c31af7Sopenharmony_ci *  a single copy op use case.
2350e5c31af7Sopenharmony_ci *
2351e5c31af7Sopenharmony_ci * The descriptors are then iterated over in ::execute(), defining the testing
2352e5c31af7Sopenharmony_ci * behavior of the test copy ops buffer storage test case.
2353e5c31af7Sopenharmony_ci */
2354e5c31af7Sopenharmony_civoid CopyOpsBufferStorageTestCase::initTestCases()
2355e5c31af7Sopenharmony_ci{
2356e5c31af7Sopenharmony_ci	/* We need to use the following destination & source BO configurations:
2357e5c31af7Sopenharmony_ci	 *
2358e5c31af7Sopenharmony_ci	 * Dst: sparse    BO 1;  Src: sparse    BO 2
2359e5c31af7Sopenharmony_ci	 * Dst: sparse    BO 1;  Src: immutable BO
2360e5c31af7Sopenharmony_ci	 * Dst: immutable BO;    Src: sparse    BO 1
2361e5c31af7Sopenharmony_ci	 * Dst: sparse    BO 1;  Src: sparse    BO 1
2362e5c31af7Sopenharmony_ci	 */
2363e5c31af7Sopenharmony_ci	unsigned int n_test_case = 0;
2364e5c31af7Sopenharmony_ci
2365e5c31af7Sopenharmony_ci	for (unsigned int n_bo_configuration = 0; n_bo_configuration < 4; /* as per the comment */
2366e5c31af7Sopenharmony_ci		 ++n_bo_configuration, ++n_test_case)
2367e5c31af7Sopenharmony_ci	{
2368e5c31af7Sopenharmony_ci		glw::GLuint		dst_bo_sparse_id = 0;
2369e5c31af7Sopenharmony_ci		bool			dst_bo_is_sparse = false;
2370e5c31af7Sopenharmony_ci		unsigned short* dst_bo_ref_data  = DE_NULL;
2371e5c31af7Sopenharmony_ci		glw::GLuint		src_bo_sparse_id = 0;
2372e5c31af7Sopenharmony_ci		bool			src_bo_is_sparse = false;
2373e5c31af7Sopenharmony_ci		unsigned short* src_bo_ref_data  = DE_NULL;
2374e5c31af7Sopenharmony_ci
2375e5c31af7Sopenharmony_ci		switch (n_bo_configuration)
2376e5c31af7Sopenharmony_ci		{
2377e5c31af7Sopenharmony_ci		case 0:
2378e5c31af7Sopenharmony_ci		{
2379e5c31af7Sopenharmony_ci			dst_bo_sparse_id = 0;
2380e5c31af7Sopenharmony_ci			dst_bo_is_sparse = true;
2381e5c31af7Sopenharmony_ci			dst_bo_ref_data  = m_ref_data[1];
2382e5c31af7Sopenharmony_ci			src_bo_sparse_id = 1;
2383e5c31af7Sopenharmony_ci			src_bo_is_sparse = true;
2384e5c31af7Sopenharmony_ci			src_bo_ref_data  = m_ref_data[2];
2385e5c31af7Sopenharmony_ci
2386e5c31af7Sopenharmony_ci			break;
2387e5c31af7Sopenharmony_ci		}
2388e5c31af7Sopenharmony_ci
2389e5c31af7Sopenharmony_ci		case 1:
2390e5c31af7Sopenharmony_ci		{
2391e5c31af7Sopenharmony_ci			dst_bo_sparse_id = 0;
2392e5c31af7Sopenharmony_ci			dst_bo_is_sparse = true;
2393e5c31af7Sopenharmony_ci			dst_bo_ref_data  = m_ref_data[1];
2394e5c31af7Sopenharmony_ci			src_bo_is_sparse = false;
2395e5c31af7Sopenharmony_ci			src_bo_ref_data  = m_ref_data[0];
2396e5c31af7Sopenharmony_ci
2397e5c31af7Sopenharmony_ci			break;
2398e5c31af7Sopenharmony_ci		}
2399e5c31af7Sopenharmony_ci
2400e5c31af7Sopenharmony_ci		case 2:
2401e5c31af7Sopenharmony_ci		{
2402e5c31af7Sopenharmony_ci			dst_bo_is_sparse = false;
2403e5c31af7Sopenharmony_ci			dst_bo_ref_data  = m_ref_data[0];
2404e5c31af7Sopenharmony_ci			src_bo_sparse_id = 0;
2405e5c31af7Sopenharmony_ci			src_bo_is_sparse = true;
2406e5c31af7Sopenharmony_ci			src_bo_ref_data  = m_ref_data[1];
2407e5c31af7Sopenharmony_ci
2408e5c31af7Sopenharmony_ci			break;
2409e5c31af7Sopenharmony_ci		}
2410e5c31af7Sopenharmony_ci
2411e5c31af7Sopenharmony_ci		case 3:
2412e5c31af7Sopenharmony_ci		{
2413e5c31af7Sopenharmony_ci			dst_bo_sparse_id = 0;
2414e5c31af7Sopenharmony_ci			dst_bo_is_sparse = true;
2415e5c31af7Sopenharmony_ci			dst_bo_ref_data  = m_ref_data[1];
2416e5c31af7Sopenharmony_ci			src_bo_sparse_id = 0;
2417e5c31af7Sopenharmony_ci			src_bo_is_sparse = true;
2418e5c31af7Sopenharmony_ci			src_bo_ref_data  = m_ref_data[1];
2419e5c31af7Sopenharmony_ci
2420e5c31af7Sopenharmony_ci			break;
2421e5c31af7Sopenharmony_ci		}
2422e5c31af7Sopenharmony_ci
2423e5c31af7Sopenharmony_ci		default:
2424e5c31af7Sopenharmony_ci		{
2425e5c31af7Sopenharmony_ci			TCU_FAIL("Invalid BO configuration index");
2426e5c31af7Sopenharmony_ci		}
2427e5c31af7Sopenharmony_ci		} /* switch (n_bo_configuration) */
2428e5c31af7Sopenharmony_ci
2429e5c31af7Sopenharmony_ci		/* Need to test the copy operation in three different scenarios,
2430e5c31af7Sopenharmony_ci		 * in regard to the destination buffer:
2431e5c31af7Sopenharmony_ci		 *
2432e5c31af7Sopenharmony_ci		 * a) All pages of the destination region are committed.
2433e5c31af7Sopenharmony_ci		 * b) Half of the pages of the destination region are committed.
2434e5c31af7Sopenharmony_ci		 * c) None of the pages of the destination region are committed.
2435e5c31af7Sopenharmony_ci		 *
2436e5c31af7Sopenharmony_ci		 * Destination region spans from 0 to half of the memory we use
2437e5c31af7Sopenharmony_ci		 * for the testing purposes.
2438e5c31af7Sopenharmony_ci		 */
2439e5c31af7Sopenharmony_ci		DE_ASSERT((m_sparse_bo_size_rounded % m_page_size) == 0);
2440e5c31af7Sopenharmony_ci		DE_ASSERT((m_sparse_bo_size_rounded % 2) == 0);
2441e5c31af7Sopenharmony_ci		DE_ASSERT((m_sparse_bo_size_rounded % 4) == 0);
2442e5c31af7Sopenharmony_ci
2443e5c31af7Sopenharmony_ci		for (unsigned int n_dst_region = 0; n_dst_region < 3; /* as per the comment */
2444e5c31af7Sopenharmony_ci			 ++n_dst_region)
2445e5c31af7Sopenharmony_ci		{
2446e5c31af7Sopenharmony_ci			glw::GLuint dst_bo_commit_size		   = 0;
2447e5c31af7Sopenharmony_ci			glw::GLuint dst_bo_commit_start_offset = 0;
2448e5c31af7Sopenharmony_ci
2449e5c31af7Sopenharmony_ci			switch (n_dst_region)
2450e5c31af7Sopenharmony_ci			{
2451e5c31af7Sopenharmony_ci			case 0:
2452e5c31af7Sopenharmony_ci			{
2453e5c31af7Sopenharmony_ci				dst_bo_commit_start_offset = 0;
2454e5c31af7Sopenharmony_ci				dst_bo_commit_size		   = m_sparse_bo_size_rounded / 2;
2455e5c31af7Sopenharmony_ci
2456e5c31af7Sopenharmony_ci				break;
2457e5c31af7Sopenharmony_ci			}
2458e5c31af7Sopenharmony_ci
2459e5c31af7Sopenharmony_ci			case 1:
2460e5c31af7Sopenharmony_ci			{
2461e5c31af7Sopenharmony_ci				dst_bo_commit_start_offset = m_sparse_bo_size_rounded / 4;
2462e5c31af7Sopenharmony_ci				dst_bo_commit_size		   = m_sparse_bo_size_rounded / 4;
2463e5c31af7Sopenharmony_ci
2464e5c31af7Sopenharmony_ci				break;
2465e5c31af7Sopenharmony_ci			}
2466e5c31af7Sopenharmony_ci
2467e5c31af7Sopenharmony_ci			case 2:
2468e5c31af7Sopenharmony_ci			{
2469e5c31af7Sopenharmony_ci				dst_bo_commit_start_offset = 0;
2470e5c31af7Sopenharmony_ci				dst_bo_commit_size		   = 0;
2471e5c31af7Sopenharmony_ci
2472e5c31af7Sopenharmony_ci				break;
2473e5c31af7Sopenharmony_ci			}
2474e5c31af7Sopenharmony_ci
2475e5c31af7Sopenharmony_ci			default:
2476e5c31af7Sopenharmony_ci			{
2477e5c31af7Sopenharmony_ci				TCU_FAIL("Invalid destination region configuration index");
2478e5c31af7Sopenharmony_ci			}
2479e5c31af7Sopenharmony_ci			} /* switch (n_dst_region) */
2480e5c31af7Sopenharmony_ci
2481e5c31af7Sopenharmony_ci			/* Same goes for the source region.
2482e5c31af7Sopenharmony_ci			 *
2483e5c31af7Sopenharmony_ci			 * Source region spans from m_sparse_bo_size_rounded / 2 to
2484e5c31af7Sopenharmony_ci			 * m_sparse_bo_size_rounded.
2485e5c31af7Sopenharmony_ci			 *
2486e5c31af7Sopenharmony_ci			 **/
2487e5c31af7Sopenharmony_ci			for (unsigned int n_src_region = 0; n_src_region < 3; /* as per the comment */
2488e5c31af7Sopenharmony_ci				 ++n_src_region)
2489e5c31af7Sopenharmony_ci			{
2490e5c31af7Sopenharmony_ci				glw::GLuint src_bo_commit_size		   = 0;
2491e5c31af7Sopenharmony_ci				glw::GLuint src_bo_commit_start_offset = 0;
2492e5c31af7Sopenharmony_ci
2493e5c31af7Sopenharmony_ci				switch (n_src_region)
2494e5c31af7Sopenharmony_ci				{
2495e5c31af7Sopenharmony_ci				case 0:
2496e5c31af7Sopenharmony_ci				{
2497e5c31af7Sopenharmony_ci					src_bo_commit_start_offset = m_sparse_bo_size_rounded / 2;
2498e5c31af7Sopenharmony_ci					src_bo_commit_size		   = m_sparse_bo_size_rounded / 2;
2499e5c31af7Sopenharmony_ci
2500e5c31af7Sopenharmony_ci					break;
2501e5c31af7Sopenharmony_ci				}
2502e5c31af7Sopenharmony_ci
2503e5c31af7Sopenharmony_ci				case 1:
2504e5c31af7Sopenharmony_ci				{
2505e5c31af7Sopenharmony_ci					src_bo_commit_start_offset = 3 * m_sparse_bo_size_rounded / 4;
2506e5c31af7Sopenharmony_ci					src_bo_commit_size		   = m_sparse_bo_size_rounded / 4;
2507e5c31af7Sopenharmony_ci
2508e5c31af7Sopenharmony_ci					break;
2509e5c31af7Sopenharmony_ci				}
2510e5c31af7Sopenharmony_ci
2511e5c31af7Sopenharmony_ci				case 2:
2512e5c31af7Sopenharmony_ci				{
2513e5c31af7Sopenharmony_ci					src_bo_commit_start_offset = m_sparse_bo_size_rounded / 2;
2514e5c31af7Sopenharmony_ci					src_bo_commit_size		   = 0;
2515e5c31af7Sopenharmony_ci
2516e5c31af7Sopenharmony_ci					break;
2517e5c31af7Sopenharmony_ci				}
2518e5c31af7Sopenharmony_ci
2519e5c31af7Sopenharmony_ci				default:
2520e5c31af7Sopenharmony_ci				{
2521e5c31af7Sopenharmony_ci					TCU_FAIL("Invalid source region configuration index");
2522e5c31af7Sopenharmony_ci				}
2523e5c31af7Sopenharmony_ci				} /* switch (n_src_region) */
2524e5c31af7Sopenharmony_ci
2525e5c31af7Sopenharmony_ci				/* Initialize the test case descriptor */
2526e5c31af7Sopenharmony_ci				_test_case test_case;
2527e5c31af7Sopenharmony_ci
2528e5c31af7Sopenharmony_ci				test_case.dst_bo_commit_size		 = dst_bo_commit_size;
2529e5c31af7Sopenharmony_ci				test_case.dst_bo_commit_start_offset = dst_bo_commit_start_offset;
2530e5c31af7Sopenharmony_ci				test_case.dst_bo_sparse_id			 = dst_bo_sparse_id;
2531e5c31af7Sopenharmony_ci				test_case.dst_bo_is_sparse			 = dst_bo_is_sparse;
2532e5c31af7Sopenharmony_ci				test_case.dst_bo_ref_data			 = dst_bo_ref_data;
2533e5c31af7Sopenharmony_ci				test_case.dst_bo_start_offset		 = static_cast<glw::GLint>(sizeof(short) * n_test_case);
2534e5c31af7Sopenharmony_ci				test_case.n_bytes_to_copy			 = static_cast<glw::GLint>(
2535e5c31af7Sopenharmony_ci					m_sparse_bo_size_rounded / 2 - test_case.dst_bo_start_offset - sizeof(short) * n_test_case);
2536e5c31af7Sopenharmony_ci				test_case.src_bo_commit_size		 = src_bo_commit_size;
2537e5c31af7Sopenharmony_ci				test_case.src_bo_commit_start_offset = src_bo_commit_start_offset;
2538e5c31af7Sopenharmony_ci				test_case.src_bo_sparse_id			 = src_bo_sparse_id;
2539e5c31af7Sopenharmony_ci				test_case.src_bo_is_sparse			 = src_bo_is_sparse;
2540e5c31af7Sopenharmony_ci				test_case.src_bo_ref_data			 = src_bo_ref_data;
2541e5c31af7Sopenharmony_ci				test_case.src_bo_start_offset		 = m_sparse_bo_size_rounded / 2;
2542e5c31af7Sopenharmony_ci
2543e5c31af7Sopenharmony_ci				DE_ASSERT(test_case.dst_bo_commit_size >= 0);
2544e5c31af7Sopenharmony_ci				DE_ASSERT(test_case.dst_bo_commit_start_offset >= 0);
2545e5c31af7Sopenharmony_ci				DE_ASSERT(test_case.dst_bo_ref_data != DE_NULL);
2546e5c31af7Sopenharmony_ci				DE_ASSERT(test_case.dst_bo_start_offset >= 0);
2547e5c31af7Sopenharmony_ci				DE_ASSERT(test_case.n_bytes_to_copy >= 0);
2548e5c31af7Sopenharmony_ci				DE_ASSERT(test_case.src_bo_commit_size >= 0);
2549e5c31af7Sopenharmony_ci				DE_ASSERT(test_case.src_bo_commit_start_offset >= 0);
2550e5c31af7Sopenharmony_ci				DE_ASSERT(test_case.src_bo_ref_data != DE_NULL);
2551e5c31af7Sopenharmony_ci				DE_ASSERT(test_case.src_bo_start_offset >= 0);
2552e5c31af7Sopenharmony_ci
2553e5c31af7Sopenharmony_ci				m_test_cases.push_back(test_case);
2554e5c31af7Sopenharmony_ci			} /* for (all source region commit configurations) */
2555e5c31af7Sopenharmony_ci		}	 /* for (all destination region commit configurations) */
2556e5c31af7Sopenharmony_ci	}		  /* for (all BO configurations which need to be tested) */
2557e5c31af7Sopenharmony_ci}
2558e5c31af7Sopenharmony_ci
2559e5c31af7Sopenharmony_ci/** Constructor.
2560e5c31af7Sopenharmony_ci *
2561e5c31af7Sopenharmony_ci *  @param gl                         GL entry-points container
2562e5c31af7Sopenharmony_ci *  @param testContext                CTS test context
2563e5c31af7Sopenharmony_ci *  @param page_size                  Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query.
2564e5c31af7Sopenharmony_ci *  @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point.
2565e5c31af7Sopenharmony_ci */
2566e5c31af7Sopenharmony_ciIndirectDispatchBufferStorageTestCase::IndirectDispatchBufferStorageTestCase(const glw::Functions& gl,
2567e5c31af7Sopenharmony_ci																			 tcu::TestContext&	 testContext,
2568e5c31af7Sopenharmony_ci																			 glw::GLint			   page_size)
2569e5c31af7Sopenharmony_ci	: m_dispatch_draw_call_args_start_offset(-1)
2570e5c31af7Sopenharmony_ci	, m_expected_ac_value(0)
2571e5c31af7Sopenharmony_ci	, m_gl(gl)
2572e5c31af7Sopenharmony_ci	, m_global_wg_size_x(2048)
2573e5c31af7Sopenharmony_ci	, m_helper_bo(0)
2574e5c31af7Sopenharmony_ci	, m_local_wg_size_x(1023) /* must stay in sync with the local work-groups's size hardcoded in m_po's body! */
2575e5c31af7Sopenharmony_ci	, m_page_size(page_size)
2576e5c31af7Sopenharmony_ci	, m_po(0)
2577e5c31af7Sopenharmony_ci	, m_sparse_bo(0)
2578e5c31af7Sopenharmony_ci	, m_sparse_bo_size(0)
2579e5c31af7Sopenharmony_ci	, m_sparse_bo_size_rounded(0)
2580e5c31af7Sopenharmony_ci	, m_testCtx(testContext)
2581e5c31af7Sopenharmony_ci{
2582e5c31af7Sopenharmony_ci	/* Left blank intentionally */
2583e5c31af7Sopenharmony_ci}
2584e5c31af7Sopenharmony_ci
2585e5c31af7Sopenharmony_ci/** Releases all GL objects used across all test case iterations.
2586e5c31af7Sopenharmony_ci *
2587e5c31af7Sopenharmony_ci *  Called once during BufferStorage test run-time.
2588e5c31af7Sopenharmony_ci */
2589e5c31af7Sopenharmony_civoid IndirectDispatchBufferStorageTestCase::deinitTestCaseGlobal()
2590e5c31af7Sopenharmony_ci{
2591e5c31af7Sopenharmony_ci	if (m_helper_bo != 0)
2592e5c31af7Sopenharmony_ci	{
2593e5c31af7Sopenharmony_ci		m_gl.deleteBuffers(1, &m_helper_bo);
2594e5c31af7Sopenharmony_ci
2595e5c31af7Sopenharmony_ci		m_helper_bo = 0;
2596e5c31af7Sopenharmony_ci	}
2597e5c31af7Sopenharmony_ci
2598e5c31af7Sopenharmony_ci	if (m_po != 0)
2599e5c31af7Sopenharmony_ci	{
2600e5c31af7Sopenharmony_ci		m_gl.deleteProgram(m_po);
2601e5c31af7Sopenharmony_ci
2602e5c31af7Sopenharmony_ci		m_po = 0;
2603e5c31af7Sopenharmony_ci	}
2604e5c31af7Sopenharmony_ci}
2605e5c31af7Sopenharmony_ci
2606e5c31af7Sopenharmony_ci/** Releases temporary GL objects, created specifically for one test case iteration. */
2607e5c31af7Sopenharmony_civoid IndirectDispatchBufferStorageTestCase::deinitTestCaseIteration()
2608e5c31af7Sopenharmony_ci{
2609e5c31af7Sopenharmony_ci	if (m_sparse_bo != 0)
2610e5c31af7Sopenharmony_ci	{
2611e5c31af7Sopenharmony_ci		m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
2612e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
2613e5c31af7Sopenharmony_ci
2614e5c31af7Sopenharmony_ci		m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,				  /* offset */
2615e5c31af7Sopenharmony_ci									 m_sparse_bo_size_rounded, GL_FALSE); /* commit */
2616e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
2617e5c31af7Sopenharmony_ci
2618e5c31af7Sopenharmony_ci		m_sparse_bo = 0;
2619e5c31af7Sopenharmony_ci	}
2620e5c31af7Sopenharmony_ci}
2621e5c31af7Sopenharmony_ci
2622e5c31af7Sopenharmony_ci/** Executes a single test iteration. The BufferStorage test will call this method
2623e5c31af7Sopenharmony_ci *  numerously during its life-time, testing various valid flag combinations applied
2624e5c31af7Sopenharmony_ci *  to the tested sparse buffer object at glBufferStorage() call time.
2625e5c31af7Sopenharmony_ci *
2626e5c31af7Sopenharmony_ci *  @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage()
2627e5c31af7Sopenharmony_ci *                                 call to set up the sparse buffer's storage.
2628e5c31af7Sopenharmony_ci *
2629e5c31af7Sopenharmony_ci *  @return true if the test case executed correctly, false otherwise.
2630e5c31af7Sopenharmony_ci */
2631e5c31af7Sopenharmony_cibool IndirectDispatchBufferStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags)
2632e5c31af7Sopenharmony_ci{
2633e5c31af7Sopenharmony_ci	(void)sparse_bo_storage_flags;
2634e5c31af7Sopenharmony_ci	bool result = true;
2635e5c31af7Sopenharmony_ci
2636e5c31af7Sopenharmony_ci	/* Set up the buffer bindings */
2637e5c31af7Sopenharmony_ci	m_gl.bindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_helper_bo);
2638e5c31af7Sopenharmony_ci	m_gl.bindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_sparse_bo);
2639e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call(s) failed");
2640e5c31af7Sopenharmony_ci
2641e5c31af7Sopenharmony_ci	m_gl.bindBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, /* index */
2642e5c31af7Sopenharmony_ci						 m_helper_bo, 12,			  /* offset */
2643e5c31af7Sopenharmony_ci						 4);						  /* size */
2644e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBufferRange() call failed.");
2645e5c31af7Sopenharmony_ci
2646e5c31af7Sopenharmony_ci	/* Bind the compute program */
2647e5c31af7Sopenharmony_ci	m_gl.useProgram(m_po);
2648e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() call failed.");
2649e5c31af7Sopenharmony_ci
2650e5c31af7Sopenharmony_ci	/* Zero out atomic counter value. */
2651e5c31af7Sopenharmony_ci	const unsigned int zero_ac_value = 0;
2652e5c31af7Sopenharmony_ci
2653e5c31af7Sopenharmony_ci	m_gl.bufferSubData(GL_ATOMIC_COUNTER_BUFFER, 12, /* offset */
2654e5c31af7Sopenharmony_ci					   4,							 /* size */
2655e5c31af7Sopenharmony_ci					   &zero_ac_value);
2656e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferSubData() call failed.");
2657e5c31af7Sopenharmony_ci
2658e5c31af7Sopenharmony_ci	m_expected_ac_value = zero_ac_value;
2659e5c31af7Sopenharmony_ci
2660e5c31af7Sopenharmony_ci	/* Run the test only in a configuration where all arguments are local in
2661e5c31af7Sopenharmony_ci	 * committed memory page(s): reading arguments from uncommitted pages means
2662e5c31af7Sopenharmony_ci	 * reading undefined data, which can result in huge dispatches that
2663e5c31af7Sopenharmony_ci	 * effectively hang the test.
2664e5c31af7Sopenharmony_ci	 */
2665e5c31af7Sopenharmony_ci	m_gl.bufferPageCommitmentARB(GL_DISPATCH_INDIRECT_BUFFER, 0,	 /* offset */
2666e5c31af7Sopenharmony_ci								 m_sparse_bo_size_rounded, GL_TRUE); /* commit */
2667e5c31af7Sopenharmony_ci
2668e5c31af7Sopenharmony_ci	m_expected_ac_value += m_global_wg_size_x * m_local_wg_size_x;
2669e5c31af7Sopenharmony_ci
2670e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call(s) failed.");
2671e5c31af7Sopenharmony_ci
2672e5c31af7Sopenharmony_ci	/* Copy the indirect dispatch call args data from the helper BO to the sparse BO */
2673e5c31af7Sopenharmony_ci	m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
2674e5c31af7Sopenharmony_ci	m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_sparse_bo);
2675e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
2676e5c31af7Sopenharmony_ci
2677e5c31af7Sopenharmony_ci	m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, /* readOffset */
2678e5c31af7Sopenharmony_ci						   m_dispatch_draw_call_args_start_offset, sizeof(unsigned int) * 3);
2679e5c31af7Sopenharmony_ci
2680e5c31af7Sopenharmony_ci	/* Run the program */
2681e5c31af7Sopenharmony_ci	m_gl.dispatchComputeIndirect(m_dispatch_draw_call_args_start_offset);
2682e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDispatchComputeIndirect() call failed.");
2683e5c31af7Sopenharmony_ci
2684e5c31af7Sopenharmony_ci	/* Extract the AC value and verify it */
2685e5c31af7Sopenharmony_ci	const unsigned int* ac_data_ptr =
2686e5c31af7Sopenharmony_ci		(const unsigned int*)m_gl.mapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 12, /* offset */
2687e5c31af7Sopenharmony_ci												 4,							   /* length */
2688e5c31af7Sopenharmony_ci												 GL_MAP_READ_BIT);
2689e5c31af7Sopenharmony_ci
2690e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMapBufferRange() call failed.");
2691e5c31af7Sopenharmony_ci
2692e5c31af7Sopenharmony_ci	if (*ac_data_ptr != m_expected_ac_value && result)
2693e5c31af7Sopenharmony_ci	{
2694e5c31af7Sopenharmony_ci		m_testCtx.getLog() << tcu::TestLog::Message << "Invalid atomic counter value encountered. "
2695e5c31af7Sopenharmony_ci													   "Expected value: ["
2696e5c31af7Sopenharmony_ci						   << m_expected_ac_value << "]"
2697e5c31af7Sopenharmony_ci													 ", found:"
2698e5c31af7Sopenharmony_ci													 "["
2699e5c31af7Sopenharmony_ci						   << *ac_data_ptr << "]." << tcu::TestLog::EndMessage;
2700e5c31af7Sopenharmony_ci
2701e5c31af7Sopenharmony_ci		result = false;
2702e5c31af7Sopenharmony_ci	}
2703e5c31af7Sopenharmony_ci
2704e5c31af7Sopenharmony_ci	/* Unmap the buffer before we move on with the next iteration */
2705e5c31af7Sopenharmony_ci	m_gl.unmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
2706e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUnmapBuffer() call failed.");
2707e5c31af7Sopenharmony_ci
2708e5c31af7Sopenharmony_ci	return result;
2709e5c31af7Sopenharmony_ci}
2710e5c31af7Sopenharmony_ci
2711e5c31af7Sopenharmony_ci/** Initializes GL objects used across all test case iterations.
2712e5c31af7Sopenharmony_ci *
2713e5c31af7Sopenharmony_ci *  Called once during BufferStorage test run-time.
2714e5c31af7Sopenharmony_ci */
2715e5c31af7Sopenharmony_cibool IndirectDispatchBufferStorageTestCase::initTestCaseGlobal()
2716e5c31af7Sopenharmony_ci{
2717e5c31af7Sopenharmony_ci	bool result = true;
2718e5c31af7Sopenharmony_ci
2719e5c31af7Sopenharmony_ci	/* One of the cases the test case implementation needs to support is the scenario
2720e5c31af7Sopenharmony_ci	 * where the indirect call arguments are located on the boundary of two (or more) memory pages,
2721e5c31af7Sopenharmony_ci	 * and some of the pages are not committed.
2722e5c31af7Sopenharmony_ci	 *
2723e5c31af7Sopenharmony_ci	 * There are two scenarios which can happen:
2724e5c31af7Sopenharmony_ci	 *
2725e5c31af7Sopenharmony_ci	 * a) page size >= sizeof(uint) * 3: Allocate two pages, arg start offset: (page_size - 4) aligned to 4.
2726e5c31af7Sopenharmony_ci	 *                                   The alignment is a must, since we'll be feeding the offset to an indirect dispatch call.
2727e5c31af7Sopenharmony_ci	 * b) page size <  sizeof(uint) * 3: Allocate as many pages as needed, disable some of the pages.
2728e5c31af7Sopenharmony_ci	 *
2729e5c31af7Sopenharmony_ci	 * For code clarity, the two cases are handled by separate branches, although they could be easily
2730e5c31af7Sopenharmony_ci	 * merged.
2731e5c31af7Sopenharmony_ci	 */
2732e5c31af7Sopenharmony_ci	const int n_indirect_dispatch_call_arg_bytes = sizeof(unsigned int) * 3;
2733e5c31af7Sopenharmony_ci
2734e5c31af7Sopenharmony_ci	if (m_page_size >= n_indirect_dispatch_call_arg_bytes)
2735e5c31af7Sopenharmony_ci	{
2736e5c31af7Sopenharmony_ci		/* Indirect dispatch call args must be aligned to 4 */
2737e5c31af7Sopenharmony_ci		DE_ASSERT(m_page_size >= 4);
2738e5c31af7Sopenharmony_ci
2739e5c31af7Sopenharmony_ci		m_dispatch_draw_call_args_start_offset = SparseBufferTestUtilities::alignOffset(m_page_size - 4, 4);
2740e5c31af7Sopenharmony_ci		m_sparse_bo_size = m_dispatch_draw_call_args_start_offset + n_indirect_dispatch_call_arg_bytes;
2741e5c31af7Sopenharmony_ci	}
2742e5c31af7Sopenharmony_ci	else
2743e5c31af7Sopenharmony_ci	{
2744e5c31af7Sopenharmony_ci		m_dispatch_draw_call_args_start_offset = 0;
2745e5c31af7Sopenharmony_ci		m_sparse_bo_size					   = n_indirect_dispatch_call_arg_bytes;
2746e5c31af7Sopenharmony_ci	}
2747e5c31af7Sopenharmony_ci
2748e5c31af7Sopenharmony_ci	m_sparse_bo_size_rounded = SparseBufferTestUtilities::alignOffset(m_sparse_bo_size, m_page_size);
2749e5c31af7Sopenharmony_ci
2750e5c31af7Sopenharmony_ci	/* Set up the helper buffer object. Its structure is as follows:
2751e5c31af7Sopenharmony_ci	 *
2752e5c31af7Sopenharmony_ci	 * [ 0-11]: Indirect dispatch call args
2753e5c31af7Sopenharmony_ci	 * [12-15]: Atomic counter value storage
2754e5c31af7Sopenharmony_ci	 */
2755e5c31af7Sopenharmony_ci	unsigned int	   helper_bo_data[4] = { 0 };
2756e5c31af7Sopenharmony_ci	const unsigned int n_helper_bo_bytes = sizeof(helper_bo_data);
2757e5c31af7Sopenharmony_ci
2758e5c31af7Sopenharmony_ci	helper_bo_data[0] = m_global_wg_size_x; /* num_groups_x */
2759e5c31af7Sopenharmony_ci	helper_bo_data[1] = 1;					/* num_groups_y */
2760e5c31af7Sopenharmony_ci	helper_bo_data[2] = 1;					/* num_groups_z */
2761e5c31af7Sopenharmony_ci	helper_bo_data[3] = 0;					/* default atomic counter value */
2762e5c31af7Sopenharmony_ci
2763e5c31af7Sopenharmony_ci	m_gl.genBuffers(1, &m_helper_bo);
2764e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
2765e5c31af7Sopenharmony_ci
2766e5c31af7Sopenharmony_ci	m_gl.bindBuffer(GL_ARRAY_BUFFER, m_helper_bo);
2767e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
2768e5c31af7Sopenharmony_ci
2769e5c31af7Sopenharmony_ci	m_gl.bufferData(GL_ARRAY_BUFFER, n_helper_bo_bytes, helper_bo_data, GL_STATIC_DRAW);
2770e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferData() call failed.");
2771e5c31af7Sopenharmony_ci
2772e5c31af7Sopenharmony_ci	/* Set up the test compute program object */
2773e5c31af7Sopenharmony_ci	static const char* cs_body = "#version 430 core\n"
2774e5c31af7Sopenharmony_ci								 "\n"
2775e5c31af7Sopenharmony_ci								 "layout(local_size_x = 1023)          in;\n"
2776e5c31af7Sopenharmony_ci								 "layout(binding      = 0, offset = 0) uniform atomic_uint ac;\n"
2777e5c31af7Sopenharmony_ci								 "\n"
2778e5c31af7Sopenharmony_ci								 "void main()\n"
2779e5c31af7Sopenharmony_ci								 "{\n"
2780e5c31af7Sopenharmony_ci								 "    atomicCounterIncrement(ac);\n"
2781e5c31af7Sopenharmony_ci								 "}\n";
2782e5c31af7Sopenharmony_ci
2783e5c31af7Sopenharmony_ci	m_po = SparseBufferTestUtilities::createComputeProgram(m_gl, &cs_body, 1); /* n_cs_body_parts */
2784e5c31af7Sopenharmony_ci
2785e5c31af7Sopenharmony_ci	result = (m_po != 0);
2786e5c31af7Sopenharmony_ci
2787e5c31af7Sopenharmony_ci	return result;
2788e5c31af7Sopenharmony_ci}
2789e5c31af7Sopenharmony_ci
2790e5c31af7Sopenharmony_ci/** Initializes GL objects which are needed for a single test case iteration.
2791e5c31af7Sopenharmony_ci *
2792e5c31af7Sopenharmony_ci *  deinitTestCaseIteration() will be called after the test case is executed in ::execute()
2793e5c31af7Sopenharmony_ci *  to release these objects.
2794e5c31af7Sopenharmony_ci **/
2795e5c31af7Sopenharmony_cibool IndirectDispatchBufferStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo)
2796e5c31af7Sopenharmony_ci{
2797e5c31af7Sopenharmony_ci	bool result = true;
2798e5c31af7Sopenharmony_ci
2799e5c31af7Sopenharmony_ci	/* Cache the BO id, if not cached already */
2800e5c31af7Sopenharmony_ci	DE_ASSERT(m_sparse_bo == 0 || m_sparse_bo == sparse_bo);
2801e5c31af7Sopenharmony_ci
2802e5c31af7Sopenharmony_ci	m_sparse_bo = sparse_bo;
2803e5c31af7Sopenharmony_ci
2804e5c31af7Sopenharmony_ci	/* Set up the sparse bufffer. */
2805e5c31af7Sopenharmony_ci	m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
2806e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
2807e5c31af7Sopenharmony_ci
2808e5c31af7Sopenharmony_ci	m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,				 /* offset */
2809e5c31af7Sopenharmony_ci								 m_sparse_bo_size_rounded, GL_TRUE); /* commit */
2810e5c31af7Sopenharmony_ci
2811e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
2812e5c31af7Sopenharmony_ci
2813e5c31af7Sopenharmony_ci	return result;
2814e5c31af7Sopenharmony_ci}
2815e5c31af7Sopenharmony_ci
2816e5c31af7Sopenharmony_ci/** Constructor.
2817e5c31af7Sopenharmony_ci *
2818e5c31af7Sopenharmony_ci *  @param gl                         GL entry-points container
2819e5c31af7Sopenharmony_ci *  @param testContext                CTS test context
2820e5c31af7Sopenharmony_ci *  @param page_size                  Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query.
2821e5c31af7Sopenharmony_ci *  @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point.
2822e5c31af7Sopenharmony_ci */
2823e5c31af7Sopenharmony_ciInvalidateBufferStorageTestCase::InvalidateBufferStorageTestCase(const glw::Functions& gl,
2824e5c31af7Sopenharmony_ci																 tcu::TestContext& testContext, glw::GLint page_size)
2825e5c31af7Sopenharmony_ci	: m_gl(gl)
2826e5c31af7Sopenharmony_ci	, m_n_pages_to_use(4)
2827e5c31af7Sopenharmony_ci	, m_page_size(page_size)
2828e5c31af7Sopenharmony_ci	, m_sparse_bo(0)
2829e5c31af7Sopenharmony_ci	, m_sparse_bo_size(0)
2830e5c31af7Sopenharmony_ci	, m_sparse_bo_size_rounded(0)
2831e5c31af7Sopenharmony_ci{
2832e5c31af7Sopenharmony_ci	(void)testContext;
2833e5c31af7Sopenharmony_ci	DE_ASSERT((m_n_pages_to_use % 2) == 0);
2834e5c31af7Sopenharmony_ci}
2835e5c31af7Sopenharmony_ci
2836e5c31af7Sopenharmony_ci/** Releases all GL objects used across all test case iterations.
2837e5c31af7Sopenharmony_ci *
2838e5c31af7Sopenharmony_ci *  Called once during BufferStorage test run-time.
2839e5c31af7Sopenharmony_ci */
2840e5c31af7Sopenharmony_civoid InvalidateBufferStorageTestCase::deinitTestCaseGlobal()
2841e5c31af7Sopenharmony_ci{
2842e5c31af7Sopenharmony_ci	/* Stub */
2843e5c31af7Sopenharmony_ci}
2844e5c31af7Sopenharmony_ci
2845e5c31af7Sopenharmony_ci/** Releases temporary GL objects, created specifically for one test case iteration. */
2846e5c31af7Sopenharmony_civoid InvalidateBufferStorageTestCase::deinitTestCaseIteration()
2847e5c31af7Sopenharmony_ci{
2848e5c31af7Sopenharmony_ci	if (m_sparse_bo != 0)
2849e5c31af7Sopenharmony_ci	{
2850e5c31af7Sopenharmony_ci		m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
2851e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
2852e5c31af7Sopenharmony_ci
2853e5c31af7Sopenharmony_ci		m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,				  /* offset */
2854e5c31af7Sopenharmony_ci									 m_sparse_bo_size_rounded, GL_FALSE); /* commit */
2855e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
2856e5c31af7Sopenharmony_ci
2857e5c31af7Sopenharmony_ci		m_sparse_bo = 0;
2858e5c31af7Sopenharmony_ci	}
2859e5c31af7Sopenharmony_ci}
2860e5c31af7Sopenharmony_ci
2861e5c31af7Sopenharmony_ci/** Executes a single test iteration. The BufferStorage test will call this method
2862e5c31af7Sopenharmony_ci *  numerously during its life-time, testing various valid flag combinations applied
2863e5c31af7Sopenharmony_ci *  to the tested sparse buffer object at glBufferStorage() call time.
2864e5c31af7Sopenharmony_ci *
2865e5c31af7Sopenharmony_ci *  @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage()
2866e5c31af7Sopenharmony_ci *                                 call to set up the sparse buffer's storage.
2867e5c31af7Sopenharmony_ci *
2868e5c31af7Sopenharmony_ci *  @return true if the test case executed correctly, false otherwise.
2869e5c31af7Sopenharmony_ci */
2870e5c31af7Sopenharmony_cibool InvalidateBufferStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags)
2871e5c31af7Sopenharmony_ci{
2872e5c31af7Sopenharmony_ci	(void)sparse_bo_storage_flags;
2873e5c31af7Sopenharmony_ci	bool result = true;
2874e5c31af7Sopenharmony_ci
2875e5c31af7Sopenharmony_ci	/* Since we cannot really perform any validation related to whether buffer
2876e5c31af7Sopenharmony_ci	 * storage invalidation works corectly, all this test can really do is to verify
2877e5c31af7Sopenharmony_ci	 * if the implementation does not crash when both entry-points are used against
2878e5c31af7Sopenharmony_ci	 * a sparse buffer object.
2879e5c31af7Sopenharmony_ci	 */
2880e5c31af7Sopenharmony_ci	for (unsigned int n_entry_point = 0; n_entry_point < 2; /* glInvalidateBuffer(), glInvalidateBufferSubData() */
2881e5c31af7Sopenharmony_ci		 ++n_entry_point)
2882e5c31af7Sopenharmony_ci	{
2883e5c31af7Sopenharmony_ci		const bool should_test_invalidate_buffer = (n_entry_point == 0);
2884e5c31af7Sopenharmony_ci
2885e5c31af7Sopenharmony_ci		/* For glInvalidateBufferSubData(), we need to test two different ranges. */
2886e5c31af7Sopenharmony_ci		for (int n_iteration = 0; n_iteration < ((should_test_invalidate_buffer) ? 1 : 2); ++n_iteration)
2887e5c31af7Sopenharmony_ci		{
2888e5c31af7Sopenharmony_ci			if (should_test_invalidate_buffer)
2889e5c31af7Sopenharmony_ci			{
2890e5c31af7Sopenharmony_ci				m_gl.invalidateBufferData(m_sparse_bo);
2891e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glInvalidateBufferData() call failed.");
2892e5c31af7Sopenharmony_ci			}
2893e5c31af7Sopenharmony_ci			else
2894e5c31af7Sopenharmony_ci			{
2895e5c31af7Sopenharmony_ci				m_gl.invalidateBufferSubData(m_sparse_bo, 0, /* offset */
2896e5c31af7Sopenharmony_ci											 m_sparse_bo_size_rounded * ((n_iteration == 0) ? 1 : 2));
2897e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glInvalidateBufferSubData() call failed.");
2898e5c31af7Sopenharmony_ci			}
2899e5c31af7Sopenharmony_ci		} /* for (all iterations) */
2900e5c31af7Sopenharmony_ci	}	 /* for (both entry-points) */
2901e5c31af7Sopenharmony_ci
2902e5c31af7Sopenharmony_ci	return result;
2903e5c31af7Sopenharmony_ci}
2904e5c31af7Sopenharmony_ci
2905e5c31af7Sopenharmony_ci/** Initializes GL objects used across all test case iterations.
2906e5c31af7Sopenharmony_ci *
2907e5c31af7Sopenharmony_ci *  Called once during BufferStorage test run-time.
2908e5c31af7Sopenharmony_ci */
2909e5c31af7Sopenharmony_cibool InvalidateBufferStorageTestCase::initTestCaseGlobal()
2910e5c31af7Sopenharmony_ci{
2911e5c31af7Sopenharmony_ci	const unsigned int n_bytes_needed = m_n_pages_to_use * m_page_size;
2912e5c31af7Sopenharmony_ci
2913e5c31af7Sopenharmony_ci	/* Determine the number of bytes both the helper and the sparse buffer
2914e5c31af7Sopenharmony_ci	 * object need to be able to hold, at maximum */
2915e5c31af7Sopenharmony_ci	m_sparse_bo_size		 = n_bytes_needed;
2916e5c31af7Sopenharmony_ci	m_sparse_bo_size_rounded = SparseBufferTestUtilities::alignOffset(n_bytes_needed, m_page_size);
2917e5c31af7Sopenharmony_ci
2918e5c31af7Sopenharmony_ci	return true;
2919e5c31af7Sopenharmony_ci}
2920e5c31af7Sopenharmony_ci
2921e5c31af7Sopenharmony_ci/** Initializes GL objects which are needed for a single test case iteration.
2922e5c31af7Sopenharmony_ci *
2923e5c31af7Sopenharmony_ci *  deinitTestCaseIteration() will be called after the test case is executed in ::execute()
2924e5c31af7Sopenharmony_ci *  to release these objects.
2925e5c31af7Sopenharmony_ci **/
2926e5c31af7Sopenharmony_cibool InvalidateBufferStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo)
2927e5c31af7Sopenharmony_ci{
2928e5c31af7Sopenharmony_ci	bool result = true;
2929e5c31af7Sopenharmony_ci
2930e5c31af7Sopenharmony_ci	/* Cache the BO id, if not cached already */
2931e5c31af7Sopenharmony_ci	DE_ASSERT(m_sparse_bo == 0 || m_sparse_bo == sparse_bo);
2932e5c31af7Sopenharmony_ci
2933e5c31af7Sopenharmony_ci	m_sparse_bo = sparse_bo;
2934e5c31af7Sopenharmony_ci
2935e5c31af7Sopenharmony_ci	/* Set up the sparse bufffer. */
2936e5c31af7Sopenharmony_ci	m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
2937e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
2938e5c31af7Sopenharmony_ci
2939e5c31af7Sopenharmony_ci	m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,				 /* offset */
2940e5c31af7Sopenharmony_ci								 m_sparse_bo_size_rounded, GL_TRUE); /* commit */
2941e5c31af7Sopenharmony_ci
2942e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
2943e5c31af7Sopenharmony_ci
2944e5c31af7Sopenharmony_ci	return result;
2945e5c31af7Sopenharmony_ci}
2946e5c31af7Sopenharmony_ci
2947e5c31af7Sopenharmony_ci/** Constructor.
2948e5c31af7Sopenharmony_ci *
2949e5c31af7Sopenharmony_ci *  @param gl                         GL entry-points container
2950e5c31af7Sopenharmony_ci *  @param testContext                CTS test context
2951e5c31af7Sopenharmony_ci *  @param page_size                  Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query.
2952e5c31af7Sopenharmony_ci *  @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point.
2953e5c31af7Sopenharmony_ci */
2954e5c31af7Sopenharmony_ciPixelPackBufferStorageTestCase::PixelPackBufferStorageTestCase(const glw::Functions& gl, tcu::TestContext& testContext,
2955e5c31af7Sopenharmony_ci															   glw::GLint page_size)
2956e5c31af7Sopenharmony_ci	: m_color_rb(0)
2957e5c31af7Sopenharmony_ci	, m_color_rb_height(1024)
2958e5c31af7Sopenharmony_ci	, m_color_rb_width(1024)
2959e5c31af7Sopenharmony_ci	, m_fbo(0)
2960e5c31af7Sopenharmony_ci	, m_gl(gl)
2961e5c31af7Sopenharmony_ci	, m_helper_bo(0)
2962e5c31af7Sopenharmony_ci	, m_page_size(page_size)
2963e5c31af7Sopenharmony_ci	, m_po(0)
2964e5c31af7Sopenharmony_ci	, m_ref_data_ptr(DE_NULL)
2965e5c31af7Sopenharmony_ci	, m_ref_data_size(0)
2966e5c31af7Sopenharmony_ci	, m_sparse_bo(0)
2967e5c31af7Sopenharmony_ci	, m_sparse_bo_size(0)
2968e5c31af7Sopenharmony_ci	, m_sparse_bo_size_rounded(0)
2969e5c31af7Sopenharmony_ci	, m_testCtx(testContext)
2970e5c31af7Sopenharmony_ci	, m_vao(0)
2971e5c31af7Sopenharmony_ci{
2972e5c31af7Sopenharmony_ci	m_ref_data_size = m_color_rb_width * m_color_rb_height * 4; /* rgba */
2973e5c31af7Sopenharmony_ci}
2974e5c31af7Sopenharmony_ci
2975e5c31af7Sopenharmony_ci/** Releases all GL objects used across all test case iterations.
2976e5c31af7Sopenharmony_ci *
2977e5c31af7Sopenharmony_ci *  Called once during BufferStorage test run-time.
2978e5c31af7Sopenharmony_ci */
2979e5c31af7Sopenharmony_civoid PixelPackBufferStorageTestCase::deinitTestCaseGlobal()
2980e5c31af7Sopenharmony_ci{
2981e5c31af7Sopenharmony_ci	if (m_color_rb != 0)
2982e5c31af7Sopenharmony_ci	{
2983e5c31af7Sopenharmony_ci		m_gl.deleteRenderbuffers(1, &m_color_rb);
2984e5c31af7Sopenharmony_ci
2985e5c31af7Sopenharmony_ci		m_color_rb = 0;
2986e5c31af7Sopenharmony_ci	}
2987e5c31af7Sopenharmony_ci
2988e5c31af7Sopenharmony_ci	if (m_fbo != 0)
2989e5c31af7Sopenharmony_ci	{
2990e5c31af7Sopenharmony_ci		m_gl.deleteFramebuffers(1, &m_fbo);
2991e5c31af7Sopenharmony_ci
2992e5c31af7Sopenharmony_ci		m_fbo = 0;
2993e5c31af7Sopenharmony_ci	}
2994e5c31af7Sopenharmony_ci
2995e5c31af7Sopenharmony_ci	if (m_helper_bo != 0)
2996e5c31af7Sopenharmony_ci	{
2997e5c31af7Sopenharmony_ci		m_gl.deleteBuffers(1, &m_helper_bo);
2998e5c31af7Sopenharmony_ci
2999e5c31af7Sopenharmony_ci		m_helper_bo = 0;
3000e5c31af7Sopenharmony_ci	}
3001e5c31af7Sopenharmony_ci
3002e5c31af7Sopenharmony_ci	if (m_ref_data_ptr != DE_NULL)
3003e5c31af7Sopenharmony_ci	{
3004e5c31af7Sopenharmony_ci		delete[] m_ref_data_ptr;
3005e5c31af7Sopenharmony_ci
3006e5c31af7Sopenharmony_ci		m_ref_data_ptr = DE_NULL;
3007e5c31af7Sopenharmony_ci	}
3008e5c31af7Sopenharmony_ci
3009e5c31af7Sopenharmony_ci	if (m_po != 0)
3010e5c31af7Sopenharmony_ci	{
3011e5c31af7Sopenharmony_ci		m_gl.deleteProgram(m_po);
3012e5c31af7Sopenharmony_ci
3013e5c31af7Sopenharmony_ci		m_po = 0;
3014e5c31af7Sopenharmony_ci	}
3015e5c31af7Sopenharmony_ci
3016e5c31af7Sopenharmony_ci	if (m_vao != 0)
3017e5c31af7Sopenharmony_ci	{
3018e5c31af7Sopenharmony_ci		m_gl.deleteVertexArrays(1, &m_vao);
3019e5c31af7Sopenharmony_ci
3020e5c31af7Sopenharmony_ci		m_vao = 0;
3021e5c31af7Sopenharmony_ci	}
3022e5c31af7Sopenharmony_ci}
3023e5c31af7Sopenharmony_ci
3024e5c31af7Sopenharmony_ci/** Releases temporary GL objects, created specifically for one test case iteration. */
3025e5c31af7Sopenharmony_civoid PixelPackBufferStorageTestCase::deinitTestCaseIteration()
3026e5c31af7Sopenharmony_ci{
3027e5c31af7Sopenharmony_ci	if (m_sparse_bo != 0)
3028e5c31af7Sopenharmony_ci	{
3029e5c31af7Sopenharmony_ci		m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
3030e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
3031e5c31af7Sopenharmony_ci
3032e5c31af7Sopenharmony_ci		m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,				  /* offset */
3033e5c31af7Sopenharmony_ci									 m_sparse_bo_size_rounded, GL_FALSE); /* commit */
3034e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
3035e5c31af7Sopenharmony_ci
3036e5c31af7Sopenharmony_ci		m_sparse_bo = 0;
3037e5c31af7Sopenharmony_ci	}
3038e5c31af7Sopenharmony_ci}
3039e5c31af7Sopenharmony_ci
3040e5c31af7Sopenharmony_ci/** Executes a single test iteration. The BufferStorage test will call this method
3041e5c31af7Sopenharmony_ci *  numerously during its life-time, testing various valid flag combinations applied
3042e5c31af7Sopenharmony_ci *  to the tested sparse buffer object at glBufferStorage() call time.
3043e5c31af7Sopenharmony_ci *
3044e5c31af7Sopenharmony_ci *  @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage()
3045e5c31af7Sopenharmony_ci *                                 call to set up the sparse buffer's storage.
3046e5c31af7Sopenharmony_ci *
3047e5c31af7Sopenharmony_ci *  @return true if the test case executed correctly, false otherwise.
3048e5c31af7Sopenharmony_ci */
3049e5c31af7Sopenharmony_cibool PixelPackBufferStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags)
3050e5c31af7Sopenharmony_ci{
3051e5c31af7Sopenharmony_ci	(void)sparse_bo_storage_flags;
3052e5c31af7Sopenharmony_ci	bool result = true;
3053e5c31af7Sopenharmony_ci
3054e5c31af7Sopenharmony_ci	m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
3055e5c31af7Sopenharmony_ci	m_gl.bindBuffer(GL_PIXEL_PACK_BUFFER, m_sparse_bo);
3056e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call(s) failed.");
3057e5c31af7Sopenharmony_ci
3058e5c31af7Sopenharmony_ci	/* Run three separate iterations:
3059e5c31af7Sopenharmony_ci	 *
3060e5c31af7Sopenharmony_ci	 * a) All pages that are going to hold the texture data are committed.
3061e5c31af7Sopenharmony_ci	 * b) Use a zig-zag memory page commitment layout patern.
3062e5c31af7Sopenharmony_ci	 * b) No pages are committed.
3063e5c31af7Sopenharmony_ci	 */
3064e5c31af7Sopenharmony_ci	for (unsigned int n_iteration = 0; n_iteration < 3; ++n_iteration)
3065e5c31af7Sopenharmony_ci	{
3066e5c31af7Sopenharmony_ci		bool result_local = true;
3067e5c31af7Sopenharmony_ci
3068e5c31af7Sopenharmony_ci		/* Set up the memory page commitment & the storage contents*/
3069e5c31af7Sopenharmony_ci		switch (n_iteration)
3070e5c31af7Sopenharmony_ci		{
3071e5c31af7Sopenharmony_ci		case 0:
3072e5c31af7Sopenharmony_ci		{
3073e5c31af7Sopenharmony_ci			m_gl.bufferPageCommitmentARB(GL_PIXEL_PACK_BUFFER, 0,			 /* offset */
3074e5c31af7Sopenharmony_ci										 m_sparse_bo_size_rounded, GL_TRUE); /* commit */
3075e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
3076e5c31af7Sopenharmony_ci
3077e5c31af7Sopenharmony_ci			break;
3078e5c31af7Sopenharmony_ci		}
3079e5c31af7Sopenharmony_ci
3080e5c31af7Sopenharmony_ci		case 1:
3081e5c31af7Sopenharmony_ci		{
3082e5c31af7Sopenharmony_ci			const unsigned int n_pages = 1 + m_ref_data_size / m_page_size;
3083e5c31af7Sopenharmony_ci
3084e5c31af7Sopenharmony_ci			DE_ASSERT((m_ref_data_size % m_page_size) == 0);
3085e5c31af7Sopenharmony_ci
3086e5c31af7Sopenharmony_ci			for (unsigned int n_page = 0; n_page < n_pages; ++n_page)
3087e5c31af7Sopenharmony_ci			{
3088e5c31af7Sopenharmony_ci				const bool should_commit = ((n_page % 2) == 0);
3089e5c31af7Sopenharmony_ci
3090e5c31af7Sopenharmony_ci				m_gl.bufferPageCommitmentARB(GL_PIXEL_PACK_BUFFER, m_page_size * n_page, m_page_size,
3091e5c31af7Sopenharmony_ci											 should_commit ? GL_TRUE : GL_FALSE);
3092e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
3093e5c31af7Sopenharmony_ci			} /* for (all relevant memory pages) */
3094e5c31af7Sopenharmony_ci
3095e5c31af7Sopenharmony_ci			break;
3096e5c31af7Sopenharmony_ci		}
3097e5c31af7Sopenharmony_ci
3098e5c31af7Sopenharmony_ci		case 2:
3099e5c31af7Sopenharmony_ci		{
3100e5c31af7Sopenharmony_ci			/* Do nothing - all pages already de-committed  */
3101e5c31af7Sopenharmony_ci			break;
3102e5c31af7Sopenharmony_ci		}
3103e5c31af7Sopenharmony_ci
3104e5c31af7Sopenharmony_ci		default:
3105e5c31af7Sopenharmony_ci		{
3106e5c31af7Sopenharmony_ci			TCU_FAIL("Invalid iteration index");
3107e5c31af7Sopenharmony_ci		}
3108e5c31af7Sopenharmony_ci		} /* switch (n_iteration) */
3109e5c31af7Sopenharmony_ci
3110e5c31af7Sopenharmony_ci		/* Draw full screen quad to generate the black-to-white gradient */
3111e5c31af7Sopenharmony_ci		const unsigned char* read_data_ptr = NULL;
3112e5c31af7Sopenharmony_ci
3113e5c31af7Sopenharmony_ci		m_gl.useProgram(m_po);
3114e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() call failed.");
3115e5c31af7Sopenharmony_ci
3116e5c31af7Sopenharmony_ci		m_gl.drawArrays(GL_TRIANGLE_STRIP, 0 /* first */, 4 /* count */);
3117e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArrays() call failed.");
3118e5c31af7Sopenharmony_ci
3119e5c31af7Sopenharmony_ci		/* Read a framebuffer pixel data */
3120e5c31af7Sopenharmony_ci		m_gl.readPixels(0,																	/* x */
3121e5c31af7Sopenharmony_ci						0,																	/* y */
3122e5c31af7Sopenharmony_ci						m_color_rb_width, m_color_rb_height, GL_RGBA, GL_UNSIGNED_BYTE, 0); /* pixels */
3123e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glReadPixels() call failed.");
3124e5c31af7Sopenharmony_ci
3125e5c31af7Sopenharmony_ci		m_gl.copyBufferSubData(GL_PIXEL_PACK_BUFFER, GL_COPY_READ_BUFFER, 0, /* readOffset */
3126e5c31af7Sopenharmony_ci							   0,											 /* writeOffset */
3127e5c31af7Sopenharmony_ci							   m_ref_data_size);
3128e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
3129e5c31af7Sopenharmony_ci
3130e5c31af7Sopenharmony_ci		read_data_ptr = (unsigned char*)m_gl.mapBufferRange(GL_COPY_READ_BUFFER, 0, /* offset */
3131e5c31af7Sopenharmony_ci															m_ref_data_size, GL_MAP_READ_BIT);
3132e5c31af7Sopenharmony_ci
3133e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMapBufferRange() call failed.");
3134e5c31af7Sopenharmony_ci
3135e5c31af7Sopenharmony_ci		/* Verify the data */
3136e5c31af7Sopenharmony_ci		unsigned int		 n_current_tex_data_byte	  = 0;
3137e5c31af7Sopenharmony_ci		const unsigned char* read_data_traveller_ptr	  = (const unsigned char*)read_data_ptr;
3138e5c31af7Sopenharmony_ci		const unsigned char* reference_data_traveller_ptr = (const unsigned char*)m_ref_data_ptr;
3139e5c31af7Sopenharmony_ci
3140e5c31af7Sopenharmony_ci		for (unsigned int y = 0; y < m_color_rb_height && result_local; ++y)
3141e5c31af7Sopenharmony_ci		{
3142e5c31af7Sopenharmony_ci			for (unsigned int x = 0; x < m_color_rb_width && result_local; ++x)
3143e5c31af7Sopenharmony_ci			{
3144e5c31af7Sopenharmony_ci				for (unsigned int n_component = 0; n_component < 4 /* rgba */ && result_local; ++n_component)
3145e5c31af7Sopenharmony_ci				{
3146e5c31af7Sopenharmony_ci					unsigned char expected_value		 = 0;
3147e5c31af7Sopenharmony_ci					bool		  is_from_committed_page = true;
3148e5c31af7Sopenharmony_ci
3149e5c31af7Sopenharmony_ci					if (n_iteration == 1) /* zig-zag */
3150e5c31af7Sopenharmony_ci					{
3151e5c31af7Sopenharmony_ci						is_from_committed_page = ((n_current_tex_data_byte / m_page_size) % 2) == 0;
3152e5c31af7Sopenharmony_ci					}
3153e5c31af7Sopenharmony_ci					else if (n_iteration == 2) /* no pages committed */
3154e5c31af7Sopenharmony_ci					{
3155e5c31af7Sopenharmony_ci						is_from_committed_page = false;
3156e5c31af7Sopenharmony_ci					}
3157e5c31af7Sopenharmony_ci
3158e5c31af7Sopenharmony_ci					if (is_from_committed_page)
3159e5c31af7Sopenharmony_ci					{
3160e5c31af7Sopenharmony_ci						expected_value = *reference_data_traveller_ptr;
3161e5c31af7Sopenharmony_ci					}
3162e5c31af7Sopenharmony_ci
3163e5c31af7Sopenharmony_ci					if (is_from_committed_page && de::abs(expected_value - *read_data_traveller_ptr) > 1)
3164e5c31af7Sopenharmony_ci					{
3165e5c31af7Sopenharmony_ci						m_testCtx.getLog() << tcu::TestLog::Message << "Invalid texel data (channel:" << n_component
3166e5c31af7Sopenharmony_ci										   << ")"
3167e5c31af7Sopenharmony_ci											  " found at X:"
3168e5c31af7Sopenharmony_ci										   << x << ", "
3169e5c31af7Sopenharmony_ci												   "Y:"
3170e5c31af7Sopenharmony_ci										   << y << ")."
3171e5c31af7Sopenharmony_ci												   " Expected value:"
3172e5c31af7Sopenharmony_ci										   << expected_value << ","
3173e5c31af7Sopenharmony_ci																" found value:"
3174e5c31af7Sopenharmony_ci										   << *reference_data_traveller_ptr << tcu::TestLog::EndMessage;
3175e5c31af7Sopenharmony_ci
3176e5c31af7Sopenharmony_ci						result_local = false;
3177e5c31af7Sopenharmony_ci					}
3178e5c31af7Sopenharmony_ci
3179e5c31af7Sopenharmony_ci					n_current_tex_data_byte++;
3180e5c31af7Sopenharmony_ci					read_data_traveller_ptr++;
3181e5c31af7Sopenharmony_ci					reference_data_traveller_ptr++;
3182e5c31af7Sopenharmony_ci				} /* for (all components) */
3183e5c31af7Sopenharmony_ci			}	 /* for (all columns) */
3184e5c31af7Sopenharmony_ci		}		  /* for (all rows) */
3185e5c31af7Sopenharmony_ci
3186e5c31af7Sopenharmony_ci		m_gl.unmapBuffer(GL_COPY_READ_BUFFER);
3187e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUnmapBuffer() call failed.");
3188e5c31af7Sopenharmony_ci
3189e5c31af7Sopenharmony_ci		read_data_ptr = DE_NULL;
3190e5c31af7Sopenharmony_ci		result &= result_local;
3191e5c31af7Sopenharmony_ci
3192e5c31af7Sopenharmony_ci		/* Clean up */
3193e5c31af7Sopenharmony_ci		m_gl.bufferPageCommitmentARB(GL_PIXEL_PACK_BUFFER, 0,			  /* offset */
3194e5c31af7Sopenharmony_ci									 m_sparse_bo_size_rounded, GL_FALSE); /* commit */
3195e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
3196e5c31af7Sopenharmony_ci	} /* for (three iterations) */
3197e5c31af7Sopenharmony_ci
3198e5c31af7Sopenharmony_ci	m_gl.bindBuffer(GL_PIXEL_PACK_BUFFER, 0);
3199e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
3200e5c31af7Sopenharmony_ci
3201e5c31af7Sopenharmony_ci	return result;
3202e5c31af7Sopenharmony_ci}
3203e5c31af7Sopenharmony_ci
3204e5c31af7Sopenharmony_ci/** Initializes GL objects used across all test case iterations.
3205e5c31af7Sopenharmony_ci *
3206e5c31af7Sopenharmony_ci *  Called once during BufferStorage test run-time.
3207e5c31af7Sopenharmony_ci */
3208e5c31af7Sopenharmony_cibool PixelPackBufferStorageTestCase::initTestCaseGlobal()
3209e5c31af7Sopenharmony_ci{
3210e5c31af7Sopenharmony_ci	/* Determine vertex shader and fragment shader that will generate black-to-white gradient. */
3211e5c31af7Sopenharmony_ci	const char* gradient_fs_code = "#version 330 core\n"
3212e5c31af7Sopenharmony_ci								   "\n"
3213e5c31af7Sopenharmony_ci								   "out vec4 result;\n"
3214e5c31af7Sopenharmony_ci								   "\n"
3215e5c31af7Sopenharmony_ci								   "void main()\n"
3216e5c31af7Sopenharmony_ci								   "{\n"
3217e5c31af7Sopenharmony_ci								   "    float c = 1.0 - (gl_FragCoord.y - 0.5) / 1023.0;\n"
3218e5c31af7Sopenharmony_ci								   "    result  = vec4(c);\n"
3219e5c31af7Sopenharmony_ci								   "}\n";
3220e5c31af7Sopenharmony_ci
3221e5c31af7Sopenharmony_ci	const char* gradient_vs_code = "#version 330\n"
3222e5c31af7Sopenharmony_ci								   "\n"
3223e5c31af7Sopenharmony_ci								   "void main()\n"
3224e5c31af7Sopenharmony_ci								   "{\n"
3225e5c31af7Sopenharmony_ci								   "    switch (gl_VertexID)\n"
3226e5c31af7Sopenharmony_ci								   "    {\n"
3227e5c31af7Sopenharmony_ci								   "        case 0: gl_Position = vec4(-1.0, -1.0, 0.0, 1.0); break;\n"
3228e5c31af7Sopenharmony_ci								   "        case 1: gl_Position = vec4( 1.0, -1.0, 0.0, 1.0); break;\n"
3229e5c31af7Sopenharmony_ci								   "        case 2: gl_Position = vec4(-1.0,  1.0, 0.0, 1.0); break;\n"
3230e5c31af7Sopenharmony_ci								   "        case 3: gl_Position = vec4( 1.0,  1.0, 0.0, 1.0); break;\n"
3231e5c31af7Sopenharmony_ci								   "    }\n"
3232e5c31af7Sopenharmony_ci								   "}\n";
3233e5c31af7Sopenharmony_ci
3234e5c31af7Sopenharmony_ci	m_po = SparseBufferTestUtilities::createProgram(m_gl, &gradient_fs_code, 1, /* n_fs_body_parts */
3235e5c31af7Sopenharmony_ci													&gradient_vs_code, 1,		/* n_vs_body_parts*/
3236e5c31af7Sopenharmony_ci													NULL,						/* attribute_names */
3237e5c31af7Sopenharmony_ci													NULL,						/* attribute_locations */
3238e5c31af7Sopenharmony_ci													GL_NONE,					/* attribute_properties */
3239e5c31af7Sopenharmony_ci													0,							/* tf_varyings */
3240e5c31af7Sopenharmony_ci													0,							/* n_tf_varyings */
3241e5c31af7Sopenharmony_ci													0);							/* tf_varying_mode */
3242e5c31af7Sopenharmony_ci	if (m_po == 0)
3243e5c31af7Sopenharmony_ci	{
3244e5c31af7Sopenharmony_ci		TCU_FAIL("Failed to link the test program");
3245e5c31af7Sopenharmony_ci	}
3246e5c31af7Sopenharmony_ci
3247e5c31af7Sopenharmony_ci	/* Generate and bind VAO */
3248e5c31af7Sopenharmony_ci	m_gl.genVertexArrays(1, &m_vao);
3249e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenVertexArrays() call failed.");
3250e5c31af7Sopenharmony_ci
3251e5c31af7Sopenharmony_ci	m_gl.bindVertexArray(m_vao);
3252e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindVertexArray() call failed.");
3253e5c31af7Sopenharmony_ci
3254e5c31af7Sopenharmony_ci	/* Generate and bind FBO */
3255e5c31af7Sopenharmony_ci	m_gl.genFramebuffers(1, &m_fbo);
3256e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenFramebuffers() call failed.");
3257e5c31af7Sopenharmony_ci
3258e5c31af7Sopenharmony_ci	m_gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
3259e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindFramebuffer() call failed.");
3260e5c31af7Sopenharmony_ci
3261e5c31af7Sopenharmony_ci	m_gl.readBuffer(GL_COLOR_ATTACHMENT0);
3262e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glReadBuffer() call failed.");
3263e5c31af7Sopenharmony_ci
3264e5c31af7Sopenharmony_ci	/* Generate and bind RBO and attach it to FBO as a color attachment */
3265e5c31af7Sopenharmony_ci	m_gl.genRenderbuffers(1, &m_color_rb);
3266e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenRenderbuffers() call failed.");
3267e5c31af7Sopenharmony_ci
3268e5c31af7Sopenharmony_ci	m_gl.bindRenderbuffer(GL_RENDERBUFFER, m_color_rb);
3269e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindRenderbuffer() call failed.");
3270e5c31af7Sopenharmony_ci
3271e5c31af7Sopenharmony_ci	m_gl.renderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, m_color_rb_width, m_color_rb_height);
3272e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glRenderbufferStorage() call failed.");
3273e5c31af7Sopenharmony_ci
3274e5c31af7Sopenharmony_ci	m_gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_color_rb);
3275e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glFramebufferRenderbuffer() call failed.");
3276e5c31af7Sopenharmony_ci
3277e5c31af7Sopenharmony_ci	if (m_gl.checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
3278e5c31af7Sopenharmony_ci	{
3279e5c31af7Sopenharmony_ci		throw tcu::NotSupportedError("Cannot execute the test - driver does not support rendering"
3280e5c31af7Sopenharmony_ci									 "to a GL_RGBA8 renderbuffer-based color attachment");
3281e5c31af7Sopenharmony_ci	}
3282e5c31af7Sopenharmony_ci
3283e5c31af7Sopenharmony_ci	m_gl.viewport(0, /* x */
3284e5c31af7Sopenharmony_ci				  0, /* y */
3285e5c31af7Sopenharmony_ci				  m_color_rb_width, m_color_rb_height);
3286e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glViewport() call failed.");
3287e5c31af7Sopenharmony_ci
3288e5c31af7Sopenharmony_ci	/* Determine what sparse buffer storage size we are going to need*/
3289e5c31af7Sopenharmony_ci	m_sparse_bo_size		 = m_ref_data_size;
3290e5c31af7Sopenharmony_ci	m_sparse_bo_size_rounded = SparseBufferTestUtilities::alignOffset(m_sparse_bo_size, m_page_size);
3291e5c31af7Sopenharmony_ci
3292e5c31af7Sopenharmony_ci	/* Prepare the texture data */
3293e5c31af7Sopenharmony_ci	unsigned char* ref_data_traveller_ptr = DE_NULL;
3294e5c31af7Sopenharmony_ci
3295e5c31af7Sopenharmony_ci	m_ref_data_ptr		   = new unsigned char[m_ref_data_size];
3296e5c31af7Sopenharmony_ci	ref_data_traveller_ptr = m_ref_data_ptr;
3297e5c31af7Sopenharmony_ci
3298e5c31af7Sopenharmony_ci	for (unsigned int y = 0; y < m_color_rb_height; ++y)
3299e5c31af7Sopenharmony_ci	{
3300e5c31af7Sopenharmony_ci		const unsigned char color = (unsigned char)((1.0f - float(y) / float(m_color_rb_height - 1)) * 255.0f);
3301e5c31af7Sopenharmony_ci
3302e5c31af7Sopenharmony_ci		for (unsigned int x = 0; x < m_color_rb_width; ++x)
3303e5c31af7Sopenharmony_ci		{
3304e5c31af7Sopenharmony_ci			memset(ref_data_traveller_ptr, color, 4); /* rgba */
3305e5c31af7Sopenharmony_ci
3306e5c31af7Sopenharmony_ci			ref_data_traveller_ptr += 4; /* rgba */
3307e5c31af7Sopenharmony_ci		}								 /* for (all columns) */
3308e5c31af7Sopenharmony_ci	}									 /* for (all rows) */
3309e5c31af7Sopenharmony_ci
3310e5c31af7Sopenharmony_ci	/* Set up the helper buffer object. */
3311e5c31af7Sopenharmony_ci	m_gl.genBuffers(1, &m_helper_bo);
3312e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
3313e5c31af7Sopenharmony_ci
3314e5c31af7Sopenharmony_ci	m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
3315e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
3316e5c31af7Sopenharmony_ci
3317e5c31af7Sopenharmony_ci	m_gl.bufferStorage(GL_COPY_READ_BUFFER, m_ref_data_size, m_ref_data_ptr, GL_MAP_READ_BIT);
3318e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed.");
3319e5c31af7Sopenharmony_ci
3320e5c31af7Sopenharmony_ci	return true;
3321e5c31af7Sopenharmony_ci}
3322e5c31af7Sopenharmony_ci
3323e5c31af7Sopenharmony_ci/** Initializes GL objects which are needed for a single test case iteration.
3324e5c31af7Sopenharmony_ci *
3325e5c31af7Sopenharmony_ci *  deinitTestCaseIteration() will be called after the test case is executed in ::execute()
3326e5c31af7Sopenharmony_ci *  to release these objects.
3327e5c31af7Sopenharmony_ci **/
3328e5c31af7Sopenharmony_cibool PixelPackBufferStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo)
3329e5c31af7Sopenharmony_ci{
3330e5c31af7Sopenharmony_ci	bool result = true;
3331e5c31af7Sopenharmony_ci
3332e5c31af7Sopenharmony_ci	/* Cache the BO id, if not cached already */
3333e5c31af7Sopenharmony_ci	DE_ASSERT(m_sparse_bo == 0 || m_sparse_bo == sparse_bo);
3334e5c31af7Sopenharmony_ci
3335e5c31af7Sopenharmony_ci	m_sparse_bo = sparse_bo;
3336e5c31af7Sopenharmony_ci
3337e5c31af7Sopenharmony_ci	return result;
3338e5c31af7Sopenharmony_ci}
3339e5c31af7Sopenharmony_ci
3340e5c31af7Sopenharmony_ci/** Constructor.
3341e5c31af7Sopenharmony_ci *
3342e5c31af7Sopenharmony_ci *  @param gl                         GL entry-points container
3343e5c31af7Sopenharmony_ci *  @param testContext                CTS test context
3344e5c31af7Sopenharmony_ci *  @param page_size                  Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query.
3345e5c31af7Sopenharmony_ci *  @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point.
3346e5c31af7Sopenharmony_ci */
3347e5c31af7Sopenharmony_ciPixelUnpackBufferStorageTestCase::PixelUnpackBufferStorageTestCase(const glw::Functions& gl,
3348e5c31af7Sopenharmony_ci																   tcu::TestContext& testContext, glw::GLint page_size)
3349e5c31af7Sopenharmony_ci	: m_gl(gl)
3350e5c31af7Sopenharmony_ci	, m_helper_bo(0)
3351e5c31af7Sopenharmony_ci	, m_page_size(page_size)
3352e5c31af7Sopenharmony_ci	, m_read_data_ptr(DE_NULL)
3353e5c31af7Sopenharmony_ci	, m_sparse_bo(0)
3354e5c31af7Sopenharmony_ci	, m_sparse_bo_size(0)
3355e5c31af7Sopenharmony_ci	, m_sparse_bo_size_rounded(0)
3356e5c31af7Sopenharmony_ci	, m_testCtx(testContext)
3357e5c31af7Sopenharmony_ci	, m_texture_data_ptr(DE_NULL)
3358e5c31af7Sopenharmony_ci	, m_texture_data_size(0)
3359e5c31af7Sopenharmony_ci	, m_to(0)
3360e5c31af7Sopenharmony_ci	, m_to_data_zero(DE_NULL)
3361e5c31af7Sopenharmony_ci	, m_to_height(1024)
3362e5c31af7Sopenharmony_ci	, m_to_width(1024)
3363e5c31af7Sopenharmony_ci{
3364e5c31af7Sopenharmony_ci	m_texture_data_size = m_to_width * m_to_height * 4; /* rgba */
3365e5c31af7Sopenharmony_ci}
3366e5c31af7Sopenharmony_ci
3367e5c31af7Sopenharmony_ci/** Releases all GL objects used across all test case iterations.
3368e5c31af7Sopenharmony_ci *
3369e5c31af7Sopenharmony_ci *  Called once during BufferStorage test run-time.
3370e5c31af7Sopenharmony_ci */
3371e5c31af7Sopenharmony_civoid PixelUnpackBufferStorageTestCase::deinitTestCaseGlobal()
3372e5c31af7Sopenharmony_ci{
3373e5c31af7Sopenharmony_ci	if (m_helper_bo != 0)
3374e5c31af7Sopenharmony_ci	{
3375e5c31af7Sopenharmony_ci		m_gl.deleteBuffers(1, &m_helper_bo);
3376e5c31af7Sopenharmony_ci
3377e5c31af7Sopenharmony_ci		m_helper_bo = 0;
3378e5c31af7Sopenharmony_ci	}
3379e5c31af7Sopenharmony_ci
3380e5c31af7Sopenharmony_ci	if (m_read_data_ptr != DE_NULL)
3381e5c31af7Sopenharmony_ci	{
3382e5c31af7Sopenharmony_ci		delete[] m_read_data_ptr;
3383e5c31af7Sopenharmony_ci
3384e5c31af7Sopenharmony_ci		m_read_data_ptr = DE_NULL;
3385e5c31af7Sopenharmony_ci	}
3386e5c31af7Sopenharmony_ci
3387e5c31af7Sopenharmony_ci	if (m_texture_data_ptr != DE_NULL)
3388e5c31af7Sopenharmony_ci	{
3389e5c31af7Sopenharmony_ci		delete[] m_texture_data_ptr;
3390e5c31af7Sopenharmony_ci
3391e5c31af7Sopenharmony_ci		m_texture_data_ptr = DE_NULL;
3392e5c31af7Sopenharmony_ci	}
3393e5c31af7Sopenharmony_ci
3394e5c31af7Sopenharmony_ci	if (m_to != 0)
3395e5c31af7Sopenharmony_ci	{
3396e5c31af7Sopenharmony_ci		m_gl.deleteTextures(1, &m_to);
3397e5c31af7Sopenharmony_ci
3398e5c31af7Sopenharmony_ci		m_to = 0;
3399e5c31af7Sopenharmony_ci	}
3400e5c31af7Sopenharmony_ci
3401e5c31af7Sopenharmony_ci	if (m_to_data_zero != DE_NULL)
3402e5c31af7Sopenharmony_ci	{
3403e5c31af7Sopenharmony_ci		delete[] m_to_data_zero;
3404e5c31af7Sopenharmony_ci
3405e5c31af7Sopenharmony_ci		m_to_data_zero = DE_NULL;
3406e5c31af7Sopenharmony_ci	}
3407e5c31af7Sopenharmony_ci}
3408e5c31af7Sopenharmony_ci
3409e5c31af7Sopenharmony_ci/** Releases temporary GL objects, created specifically for one test case iteration. */
3410e5c31af7Sopenharmony_civoid PixelUnpackBufferStorageTestCase::deinitTestCaseIteration()
3411e5c31af7Sopenharmony_ci{
3412e5c31af7Sopenharmony_ci	if (m_sparse_bo != 0)
3413e5c31af7Sopenharmony_ci	{
3414e5c31af7Sopenharmony_ci		m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
3415e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
3416e5c31af7Sopenharmony_ci
3417e5c31af7Sopenharmony_ci		m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,				  /* offset */
3418e5c31af7Sopenharmony_ci									 m_sparse_bo_size_rounded, GL_FALSE); /* commit */
3419e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
3420e5c31af7Sopenharmony_ci
3421e5c31af7Sopenharmony_ci		m_sparse_bo = 0;
3422e5c31af7Sopenharmony_ci	}
3423e5c31af7Sopenharmony_ci}
3424e5c31af7Sopenharmony_ci
3425e5c31af7Sopenharmony_ci/** Executes a single test iteration. The BufferStorage test will call this method
3426e5c31af7Sopenharmony_ci *  numerously during its life-time, testing various valid flag combinations applied
3427e5c31af7Sopenharmony_ci *  to the tested sparse buffer object at glBufferStorage() call time.
3428e5c31af7Sopenharmony_ci *
3429e5c31af7Sopenharmony_ci *  @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage()
3430e5c31af7Sopenharmony_ci *                                 call to set up the sparse buffer's storage.
3431e5c31af7Sopenharmony_ci *
3432e5c31af7Sopenharmony_ci *  @return true if the test case executed correctly, false otherwise.
3433e5c31af7Sopenharmony_ci */
3434e5c31af7Sopenharmony_cibool PixelUnpackBufferStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags)
3435e5c31af7Sopenharmony_ci{
3436e5c31af7Sopenharmony_ci	(void)sparse_bo_storage_flags;
3437e5c31af7Sopenharmony_ci	bool result = true;
3438e5c31af7Sopenharmony_ci
3439e5c31af7Sopenharmony_ci	m_gl.bindBuffer(GL_PIXEL_UNPACK_BUFFER, m_sparse_bo);
3440e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
3441e5c31af7Sopenharmony_ci
3442e5c31af7Sopenharmony_ci	m_gl.bindTexture(GL_TEXTURE_2D, m_to);
3443e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindTexture() call failed.");
3444e5c31af7Sopenharmony_ci
3445e5c31af7Sopenharmony_ci	m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
3446e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindTexture() call failed.");
3447e5c31af7Sopenharmony_ci
3448e5c31af7Sopenharmony_ci	/* Run three separate iterations:
3449e5c31af7Sopenharmony_ci	 *
3450e5c31af7Sopenharmony_ci	 * a) All pages holding the source texture data are committed.
3451e5c31af7Sopenharmony_ci	 * b) Use a zig-zag memory page commitment layout patern.
3452e5c31af7Sopenharmony_ci	 * b) No pages are committed.
3453e5c31af7Sopenharmony_ci	 */
3454e5c31af7Sopenharmony_ci	for (unsigned int n_iteration = 0; n_iteration < 3; ++n_iteration)
3455e5c31af7Sopenharmony_ci	{
3456e5c31af7Sopenharmony_ci		bool result_local = true;
3457e5c31af7Sopenharmony_ci
3458e5c31af7Sopenharmony_ci		/* Set up the memory page commitment & the storage contents*/
3459e5c31af7Sopenharmony_ci		switch (n_iteration)
3460e5c31af7Sopenharmony_ci		{
3461e5c31af7Sopenharmony_ci		case 0:
3462e5c31af7Sopenharmony_ci		{
3463e5c31af7Sopenharmony_ci			m_gl.bufferPageCommitmentARB(GL_PIXEL_UNPACK_BUFFER, 0,			 /* offset */
3464e5c31af7Sopenharmony_ci										 m_sparse_bo_size_rounded, GL_TRUE); /* commit */
3465e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
3466e5c31af7Sopenharmony_ci
3467e5c31af7Sopenharmony_ci			m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_PIXEL_UNPACK_BUFFER, 0, /* readOffset */
3468e5c31af7Sopenharmony_ci								   0,											   /* writeOffset */
3469e5c31af7Sopenharmony_ci								   m_texture_data_size);
3470e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
3471e5c31af7Sopenharmony_ci
3472e5c31af7Sopenharmony_ci			break;
3473e5c31af7Sopenharmony_ci		}
3474e5c31af7Sopenharmony_ci
3475e5c31af7Sopenharmony_ci		case 1:
3476e5c31af7Sopenharmony_ci		{
3477e5c31af7Sopenharmony_ci			const unsigned int n_pages = m_texture_data_size / m_page_size;
3478e5c31af7Sopenharmony_ci
3479e5c31af7Sopenharmony_ci			for (unsigned int n_page = 0; n_page < n_pages; ++n_page)
3480e5c31af7Sopenharmony_ci			{
3481e5c31af7Sopenharmony_ci				const bool should_commit = ((n_page % 2) == 0);
3482e5c31af7Sopenharmony_ci
3483e5c31af7Sopenharmony_ci				m_gl.bufferPageCommitmentARB(GL_PIXEL_UNPACK_BUFFER, m_page_size * n_page, m_page_size,
3484e5c31af7Sopenharmony_ci											 should_commit ? GL_TRUE : GL_FALSE);
3485e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
3486e5c31af7Sopenharmony_ci
3487e5c31af7Sopenharmony_ci				if (should_commit)
3488e5c31af7Sopenharmony_ci				{
3489e5c31af7Sopenharmony_ci					m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_PIXEL_UNPACK_BUFFER,
3490e5c31af7Sopenharmony_ci										   m_page_size * n_page, /* readOffset */
3491e5c31af7Sopenharmony_ci										   m_page_size * n_page, /* writeOffset */
3492e5c31af7Sopenharmony_ci										   m_page_size);
3493e5c31af7Sopenharmony_ci					GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
3494e5c31af7Sopenharmony_ci				}
3495e5c31af7Sopenharmony_ci			} /* for (all relevant memory pages) */
3496e5c31af7Sopenharmony_ci
3497e5c31af7Sopenharmony_ci			break;
3498e5c31af7Sopenharmony_ci		}
3499e5c31af7Sopenharmony_ci
3500e5c31af7Sopenharmony_ci		case 2:
3501e5c31af7Sopenharmony_ci		{
3502e5c31af7Sopenharmony_ci			/* Do nothing */
3503e5c31af7Sopenharmony_ci			break;
3504e5c31af7Sopenharmony_ci		}
3505e5c31af7Sopenharmony_ci
3506e5c31af7Sopenharmony_ci		default:
3507e5c31af7Sopenharmony_ci		{
3508e5c31af7Sopenharmony_ci			TCU_FAIL("Invalid iteration index");
3509e5c31af7Sopenharmony_ci		}
3510e5c31af7Sopenharmony_ci		} /* switch (n_iteration) */
3511e5c31af7Sopenharmony_ci
3512e5c31af7Sopenharmony_ci		/* Clean up the base mip-map's contents before we proceeding with updating it
3513e5c31af7Sopenharmony_ci		 * with data downloaded from the BO, in order to avoid situation where silently
3514e5c31af7Sopenharmony_ci		 * failing glTexSubImage2D() calls slip past unnoticed */
3515e5c31af7Sopenharmony_ci		m_gl.bindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
3516e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
3517e5c31af7Sopenharmony_ci
3518e5c31af7Sopenharmony_ci		m_gl.texSubImage2D(GL_TEXTURE_2D, 0, /* level */
3519e5c31af7Sopenharmony_ci						   0,				 /* xoffset */
3520e5c31af7Sopenharmony_ci						   0,				 /* yoffset */
3521e5c31af7Sopenharmony_ci						   m_to_width, m_to_height, GL_RGBA, GL_UNSIGNED_BYTE, m_to_data_zero);
3522e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glTexSubImage2D() call failed.");
3523e5c31af7Sopenharmony_ci
3524e5c31af7Sopenharmony_ci		m_gl.bindBuffer(GL_PIXEL_UNPACK_BUFFER, m_sparse_bo);
3525e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
3526e5c31af7Sopenharmony_ci
3527e5c31af7Sopenharmony_ci		/* Update the base mip-map's contents */
3528e5c31af7Sopenharmony_ci		m_gl.texSubImage2D(GL_TEXTURE_2D, 0, /* level */
3529e5c31af7Sopenharmony_ci						   0,				 /* xoffset */
3530e5c31af7Sopenharmony_ci						   0,				 /* yoffset */
3531e5c31af7Sopenharmony_ci						   m_to_width, m_to_height, GL_RGBA, GL_UNSIGNED_BYTE, (const glw::GLvoid*)0);
3532e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glTexSubImage2D() call failed.");
3533e5c31af7Sopenharmony_ci
3534e5c31af7Sopenharmony_ci		/* Read back the stored mip-map data */
3535e5c31af7Sopenharmony_ci		memset(m_read_data_ptr, 0xFF, m_texture_data_size);
3536e5c31af7Sopenharmony_ci
3537e5c31af7Sopenharmony_ci		m_gl.getTexImage(GL_TEXTURE_2D, 0, /* level */
3538e5c31af7Sopenharmony_ci						 GL_RGBA, GL_UNSIGNED_BYTE, m_read_data_ptr);
3539e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetTexImage() call failed.");
3540e5c31af7Sopenharmony_ci
3541e5c31af7Sopenharmony_ci		/* Verify the data */
3542e5c31af7Sopenharmony_ci		unsigned int n_current_tex_data_byte	= 0;
3543e5c31af7Sopenharmony_ci		const char*  read_data_traveller_ptr	= (const char*)m_read_data_ptr;
3544e5c31af7Sopenharmony_ci		const char*  texture_data_traveller_ptr = (const char*)m_texture_data_ptr;
3545e5c31af7Sopenharmony_ci
3546e5c31af7Sopenharmony_ci		for (unsigned int y = 0; y < m_to_height && result_local; ++y)
3547e5c31af7Sopenharmony_ci		{
3548e5c31af7Sopenharmony_ci			for (unsigned int x = 0; x < m_to_width && result_local; ++x)
3549e5c31af7Sopenharmony_ci			{
3550e5c31af7Sopenharmony_ci				for (unsigned int n_component = 0; n_component < 4 /* rgba */ && result_local; ++n_component)
3551e5c31af7Sopenharmony_ci				{
3552e5c31af7Sopenharmony_ci					char expected_value			= 0;
3553e5c31af7Sopenharmony_ci					bool is_from_committed_page = true;
3554e5c31af7Sopenharmony_ci
3555e5c31af7Sopenharmony_ci					if (n_iteration == 1) /* zig-zag */
3556e5c31af7Sopenharmony_ci					{
3557e5c31af7Sopenharmony_ci						is_from_committed_page = ((n_current_tex_data_byte / m_page_size) % 2) == 0;
3558e5c31af7Sopenharmony_ci					}
3559e5c31af7Sopenharmony_ci					else if (n_iteration == 2) /* no pages committed */
3560e5c31af7Sopenharmony_ci					{
3561e5c31af7Sopenharmony_ci						is_from_committed_page = false;
3562e5c31af7Sopenharmony_ci					}
3563e5c31af7Sopenharmony_ci
3564e5c31af7Sopenharmony_ci					if (is_from_committed_page)
3565e5c31af7Sopenharmony_ci					{
3566e5c31af7Sopenharmony_ci						expected_value = *texture_data_traveller_ptr;
3567e5c31af7Sopenharmony_ci					}
3568e5c31af7Sopenharmony_ci
3569e5c31af7Sopenharmony_ci					if (is_from_committed_page && de::abs(expected_value - *read_data_traveller_ptr) >= 1)
3570e5c31af7Sopenharmony_ci					{
3571e5c31af7Sopenharmony_ci						m_testCtx.getLog() << tcu::TestLog::Message << "Invalid texel data (channel:" << n_component
3572e5c31af7Sopenharmony_ci										   << ")"
3573e5c31af7Sopenharmony_ci											  " found at X:"
3574e5c31af7Sopenharmony_ci										   << x << ", "
3575e5c31af7Sopenharmony_ci												   "Y:"
3576e5c31af7Sopenharmony_ci										   << y << ")."
3577e5c31af7Sopenharmony_ci												   " Expected value:"
3578e5c31af7Sopenharmony_ci										   << expected_value << ","
3579e5c31af7Sopenharmony_ci																" found value:"
3580e5c31af7Sopenharmony_ci										   << *read_data_traveller_ptr << tcu::TestLog::EndMessage;
3581e5c31af7Sopenharmony_ci
3582e5c31af7Sopenharmony_ci						result_local = false;
3583e5c31af7Sopenharmony_ci					}
3584e5c31af7Sopenharmony_ci
3585e5c31af7Sopenharmony_ci					n_current_tex_data_byte++;
3586e5c31af7Sopenharmony_ci					read_data_traveller_ptr++;
3587e5c31af7Sopenharmony_ci					texture_data_traveller_ptr++;
3588e5c31af7Sopenharmony_ci				} /* for (all components) */
3589e5c31af7Sopenharmony_ci			}	 /* for (all columns) */
3590e5c31af7Sopenharmony_ci		}		  /* for (all rows) */
3591e5c31af7Sopenharmony_ci
3592e5c31af7Sopenharmony_ci		result &= result_local;
3593e5c31af7Sopenharmony_ci
3594e5c31af7Sopenharmony_ci		/* Clean up */
3595e5c31af7Sopenharmony_ci		m_gl.bufferPageCommitmentARB(GL_PIXEL_UNPACK_BUFFER, 0,			  /* offset */
3596e5c31af7Sopenharmony_ci									 m_sparse_bo_size_rounded, GL_FALSE); /* commit */
3597e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
3598e5c31af7Sopenharmony_ci	} /* for (three iterations) */
3599e5c31af7Sopenharmony_ci
3600e5c31af7Sopenharmony_ci	m_gl.bindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
3601e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
3602e5c31af7Sopenharmony_ci
3603e5c31af7Sopenharmony_ci	return result;
3604e5c31af7Sopenharmony_ci}
3605e5c31af7Sopenharmony_ci
3606e5c31af7Sopenharmony_ci/** Initializes GL objects used across all test case iterations.
3607e5c31af7Sopenharmony_ci *
3608e5c31af7Sopenharmony_ci *  Called once during BufferStorage test run-time.
3609e5c31af7Sopenharmony_ci */
3610e5c31af7Sopenharmony_cibool PixelUnpackBufferStorageTestCase::initTestCaseGlobal()
3611e5c31af7Sopenharmony_ci{
3612e5c31af7Sopenharmony_ci	/* Determine sparse buffer storage size */
3613e5c31af7Sopenharmony_ci	m_sparse_bo_size		 = m_texture_data_size;
3614e5c31af7Sopenharmony_ci	m_sparse_bo_size_rounded = SparseBufferTestUtilities::alignOffset(m_sparse_bo_size, m_page_size);
3615e5c31af7Sopenharmony_ci
3616e5c31af7Sopenharmony_ci	/* Prepare the texture data */
3617e5c31af7Sopenharmony_ci	unsigned char* texture_data_traveller_ptr = DE_NULL;
3618e5c31af7Sopenharmony_ci
3619e5c31af7Sopenharmony_ci	m_read_data_ptr			   = new unsigned char[m_texture_data_size];
3620e5c31af7Sopenharmony_ci	m_texture_data_ptr		   = new unsigned char[m_texture_data_size];
3621e5c31af7Sopenharmony_ci	texture_data_traveller_ptr = m_texture_data_ptr;
3622e5c31af7Sopenharmony_ci
3623e5c31af7Sopenharmony_ci	for (unsigned int y = 0; y < m_to_height; ++y)
3624e5c31af7Sopenharmony_ci	{
3625e5c31af7Sopenharmony_ci		for (unsigned int x = 0; x < m_to_width; ++x)
3626e5c31af7Sopenharmony_ci		{
3627e5c31af7Sopenharmony_ci			const unsigned char color = (unsigned char)(float(x) / float(m_to_width - 1) * 255.0f);
3628e5c31af7Sopenharmony_ci
3629e5c31af7Sopenharmony_ci			memset(texture_data_traveller_ptr, color, 4); /* rgba */
3630e5c31af7Sopenharmony_ci
3631e5c31af7Sopenharmony_ci			texture_data_traveller_ptr += 4; /* rgba */
3632e5c31af7Sopenharmony_ci		}									 /* for (all columns) */
3633e5c31af7Sopenharmony_ci	}										 /* for (all rows) */
3634e5c31af7Sopenharmony_ci
3635e5c31af7Sopenharmony_ci	m_to_data_zero = new unsigned char[m_texture_data_size];
3636e5c31af7Sopenharmony_ci
3637e5c31af7Sopenharmony_ci	memset(m_to_data_zero, 0, m_texture_data_size);
3638e5c31af7Sopenharmony_ci
3639e5c31af7Sopenharmony_ci	/* Set up the helper buffer object */
3640e5c31af7Sopenharmony_ci	m_gl.genBuffers(1, &m_helper_bo);
3641e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
3642e5c31af7Sopenharmony_ci
3643e5c31af7Sopenharmony_ci	m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
3644e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
3645e5c31af7Sopenharmony_ci
3646e5c31af7Sopenharmony_ci	m_gl.bufferStorage(GL_COPY_READ_BUFFER, m_texture_data_size, m_texture_data_ptr, GL_MAP_READ_BIT);
3647e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed.");
3648e5c31af7Sopenharmony_ci
3649e5c31af7Sopenharmony_ci	/* Set up texture object storage */
3650e5c31af7Sopenharmony_ci	m_gl.genTextures(1, &m_to);
3651e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenTextures() call failed.");
3652e5c31af7Sopenharmony_ci
3653e5c31af7Sopenharmony_ci	m_gl.bindTexture(GL_TEXTURE_2D, m_to);
3654e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindTexture() call failed.");
3655e5c31af7Sopenharmony_ci
3656e5c31af7Sopenharmony_ci	m_gl.texStorage2D(GL_TEXTURE_2D, 1, /* levels */
3657e5c31af7Sopenharmony_ci					  GL_RGBA8, m_to_width, m_to_height);
3658e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glTexStorage2D() call failed.");
3659e5c31af7Sopenharmony_ci
3660e5c31af7Sopenharmony_ci	return true;
3661e5c31af7Sopenharmony_ci}
3662e5c31af7Sopenharmony_ci
3663e5c31af7Sopenharmony_ci/** Initializes GL objects which are needed for a single test case iteration.
3664e5c31af7Sopenharmony_ci *
3665e5c31af7Sopenharmony_ci *  deinitTestCaseIteration() will be called after the test case is executed in ::execute()
3666e5c31af7Sopenharmony_ci *  to release these objects.
3667e5c31af7Sopenharmony_ci **/
3668e5c31af7Sopenharmony_cibool PixelUnpackBufferStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo)
3669e5c31af7Sopenharmony_ci{
3670e5c31af7Sopenharmony_ci	bool result = true;
3671e5c31af7Sopenharmony_ci
3672e5c31af7Sopenharmony_ci	/* Cache the BO id, if not cached already */
3673e5c31af7Sopenharmony_ci	DE_ASSERT(m_sparse_bo == 0 || m_sparse_bo == sparse_bo);
3674e5c31af7Sopenharmony_ci
3675e5c31af7Sopenharmony_ci	m_sparse_bo = sparse_bo;
3676e5c31af7Sopenharmony_ci
3677e5c31af7Sopenharmony_ci	return result;
3678e5c31af7Sopenharmony_ci}
3679e5c31af7Sopenharmony_ci
3680e5c31af7Sopenharmony_ci/** Constructor.
3681e5c31af7Sopenharmony_ci *
3682e5c31af7Sopenharmony_ci *  @param gl                         GL entry-points container
3683e5c31af7Sopenharmony_ci *  @param testContext                CTS test context
3684e5c31af7Sopenharmony_ci *  @param page_size                  Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query.
3685e5c31af7Sopenharmony_ci *  @param ibo_usage                  Specifies if an indexed draw call should be used by the test. For more details,
3686e5c31af7Sopenharmony_ci *                                    please see documentation for _ibo_usage.
3687e5c31af7Sopenharmony_ci *  @param use_color_data             true to use the color data for the tested draw call;
3688e5c31af7Sopenharmony_ci *                                    false to omit usage of attribute data.
3689e5c31af7Sopenharmony_ci *  @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point.
3690e5c31af7Sopenharmony_ci */
3691e5c31af7Sopenharmony_ciQuadsBufferStorageTestCase::QuadsBufferStorageTestCase(const glw::Functions& gl, tcu::TestContext& testContext,
3692e5c31af7Sopenharmony_ci													   glw::GLint page_size, _ibo_usage ibo_usage, bool use_color_data)
3693e5c31af7Sopenharmony_ci	: m_attribute_color_location(0)	/* predefined attribute locations */
3694e5c31af7Sopenharmony_ci	, m_attribute_position_location(1) /* predefined attribute locations */
3695e5c31af7Sopenharmony_ci	, m_color_data_offset(0)
3696e5c31af7Sopenharmony_ci	, m_data(DE_NULL)
3697e5c31af7Sopenharmony_ci	, m_data_size(0)
3698e5c31af7Sopenharmony_ci	, m_data_size_rounded(0)
3699e5c31af7Sopenharmony_ci	, m_fbo(0)
3700e5c31af7Sopenharmony_ci	, m_gl(gl)
3701e5c31af7Sopenharmony_ci	, m_helper_bo(0)
3702e5c31af7Sopenharmony_ci	, m_ibo_data_offset(-1)
3703e5c31af7Sopenharmony_ci	, m_ibo_usage(ibo_usage)
3704e5c31af7Sopenharmony_ci	, m_n_quad_delta_x(5)
3705e5c31af7Sopenharmony_ci	, m_n_quad_delta_y(5)
3706e5c31af7Sopenharmony_ci	, m_n_quad_height(5)
3707e5c31af7Sopenharmony_ci	, m_n_quad_width(5)
3708e5c31af7Sopenharmony_ci	, m_n_quads_x(100) /* as per spec */
3709e5c31af7Sopenharmony_ci	, m_n_quads_y(100) /* as per spec */
3710e5c31af7Sopenharmony_ci	, m_n_vertices_to_draw(0)
3711e5c31af7Sopenharmony_ci	, m_pages_committed(false)
3712e5c31af7Sopenharmony_ci	, m_po(0)
3713e5c31af7Sopenharmony_ci	, m_sparse_bo(0)
3714e5c31af7Sopenharmony_ci	, m_testCtx(testContext)
3715e5c31af7Sopenharmony_ci	, m_to(0)
3716e5c31af7Sopenharmony_ci	, m_to_height(1024) /* as per spec */
3717e5c31af7Sopenharmony_ci	, m_to_width(1024)  /* as per spec */
3718e5c31af7Sopenharmony_ci	, m_use_color_data(use_color_data)
3719e5c31af7Sopenharmony_ci	, m_vao(0)
3720e5c31af7Sopenharmony_ci	, m_vbo_data_offset(-1)
3721e5c31af7Sopenharmony_ci{
3722e5c31af7Sopenharmony_ci	/*
3723e5c31af7Sopenharmony_ci	 * Each quad = 2 triangles, 1 triangle = 3 vertices, 1 vertex = 4 components.
3724e5c31af7Sopenharmony_ci	 * The inefficient representation has been used on purpose - we want the data to take
3725e5c31af7Sopenharmony_ci	 * more than 64KB so that it is guaranteed that it will span over more than 1 page.
3726e5c31af7Sopenharmony_ci	 */
3727e5c31af7Sopenharmony_ci	m_data_size = 0;
3728e5c31af7Sopenharmony_ci
3729e5c31af7Sopenharmony_ci	m_n_vertices_to_draw = m_n_quads_x * /* quads in X */
3730e5c31af7Sopenharmony_ci						   m_n_quads_y * /* quads in Y */
3731e5c31af7Sopenharmony_ci						   2 *			 /* triangles */
3732e5c31af7Sopenharmony_ci						   3;			 /* vertices per triangle */
3733e5c31af7Sopenharmony_ci
3734e5c31af7Sopenharmony_ci	m_data_size = static_cast<glw::GLuint>(m_n_vertices_to_draw * 4 /* components */ * sizeof(float));
3735e5c31af7Sopenharmony_ci
3736e5c31af7Sopenharmony_ci	if (m_ibo_usage != IBO_USAGE_NONE)
3737e5c31af7Sopenharmony_ci	{
3738e5c31af7Sopenharmony_ci		DE_ASSERT(m_n_vertices_to_draw < 65536);
3739e5c31af7Sopenharmony_ci
3740e5c31af7Sopenharmony_ci		m_data_size = static_cast<glw::GLuint>(m_data_size + (m_n_vertices_to_draw * sizeof(unsigned short)));
3741e5c31af7Sopenharmony_ci	}
3742e5c31af7Sopenharmony_ci
3743e5c31af7Sopenharmony_ci	if (m_use_color_data)
3744e5c31af7Sopenharmony_ci	{
3745e5c31af7Sopenharmony_ci		m_data_size = static_cast<glw::GLuint>(m_data_size +
3746e5c31af7Sopenharmony_ci											   (m_n_vertices_to_draw * sizeof(unsigned char) * 4 * /* rgba components */
3747e5c31af7Sopenharmony_ci												2 *												   /* triangles */
3748e5c31af7Sopenharmony_ci												3)); /* vertices per triangle */
3749e5c31af7Sopenharmony_ci	}
3750e5c31af7Sopenharmony_ci
3751e5c31af7Sopenharmony_ci	m_data_size_rounded = SparseBufferTestUtilities::alignOffset(m_data_size, page_size);
3752e5c31af7Sopenharmony_ci}
3753e5c31af7Sopenharmony_ci
3754e5c31af7Sopenharmony_ci/** Allocates a data buffer and fills it with vertex/index/color data. Vertex data is always stored,
3755e5c31af7Sopenharmony_ci *  index data only if m_ibo_usage is different from IBO_USAGE_NONE. Color data is only saved if
3756e5c31af7Sopenharmony_ci *  m_use_color_data is true.
3757e5c31af7Sopenharmony_ci *
3758e5c31af7Sopenharmony_ci *  @param out_data              Deref will be used to store a pointer to the allocated data buffer.
3759e5c31af7Sopenharmony_ci *                               Ownership is transferred to the caller. Must not be NULL.
3760e5c31af7Sopenharmony_ci *  @param out_vbo_data_offset   Deref will be used to store an offset, from which VBO data starts,
3761e5c31af7Sopenharmony_ci *                               relative to the beginning of *out_data. Must not be NULL.
3762e5c31af7Sopenharmony_ci *  @param out_ibo_data_offset   Deref will be used to store an offset, from which IBO data starts,
3763e5c31af7Sopenharmony_ci *                               relative to the beginning of *out_data. May be NULL if m_ibo_usage
3764e5c31af7Sopenharmony_ci *                               is IBO_USAGE_NONE.
3765e5c31af7Sopenharmony_ci *  @param out_color_data_offset Deref will be used to store na offset, from which color data starts,
3766e5c31af7Sopenharmony_ci *                               relative to the beginning of *out_data. May be NULL if m_use_color_data
3767e5c31af7Sopenharmony_ci *                               is false.
3768e5c31af7Sopenharmony_ci *
3769e5c31af7Sopenharmony_ci */
3770e5c31af7Sopenharmony_civoid QuadsBufferStorageTestCase::createTestData(unsigned char** out_data, unsigned int* out_vbo_data_offset,
3771e5c31af7Sopenharmony_ci												unsigned int* out_ibo_data_offset,
3772e5c31af7Sopenharmony_ci												unsigned int* out_color_data_offset) const
3773e5c31af7Sopenharmony_ci{
3774e5c31af7Sopenharmony_ci	unsigned char* data_traveller_ptr = NULL;
3775e5c31af7Sopenharmony_ci
3776e5c31af7Sopenharmony_ci	*out_data			 = new unsigned char[m_data_size];
3777e5c31af7Sopenharmony_ci	*out_vbo_data_offset = 0;
3778e5c31af7Sopenharmony_ci
3779e5c31af7Sopenharmony_ci	data_traveller_ptr = *out_data;
3780e5c31af7Sopenharmony_ci
3781e5c31af7Sopenharmony_ci	for (unsigned int n_quad_y = 0; n_quad_y < m_n_quads_y; ++n_quad_y)
3782e5c31af7Sopenharmony_ci	{
3783e5c31af7Sopenharmony_ci		for (unsigned int n_quad_x = 0; n_quad_x < m_n_quads_x; ++n_quad_x)
3784e5c31af7Sopenharmony_ci		{
3785e5c31af7Sopenharmony_ci			const unsigned int quad_start_x_px = n_quad_x * (m_n_quad_delta_x + m_n_quad_width);
3786e5c31af7Sopenharmony_ci			const unsigned int quad_start_y_px = n_quad_y * (m_n_quad_delta_y + m_n_quad_height);
3787e5c31af7Sopenharmony_ci			const unsigned int quad_end_x_px   = quad_start_x_px + m_n_quad_width;
3788e5c31af7Sopenharmony_ci			const unsigned int quad_end_y_px   = quad_start_y_px + m_n_quad_height;
3789e5c31af7Sopenharmony_ci
3790e5c31af7Sopenharmony_ci			const float quad_end_x_ss   = float(quad_end_x_px) / float(m_to_width) * 2.0f - 1.0f;
3791e5c31af7Sopenharmony_ci			const float quad_end_y_ss   = float(quad_end_y_px) / float(m_to_height) * 2.0f - 1.0f;
3792e5c31af7Sopenharmony_ci			const float quad_start_x_ss = float(quad_start_x_px) / float(m_to_width) * 2.0f - 1.0f;
3793e5c31af7Sopenharmony_ci			const float quad_start_y_ss = float(quad_start_y_px) / float(m_to_height) * 2.0f - 1.0f;
3794e5c31af7Sopenharmony_ci
3795e5c31af7Sopenharmony_ci			/*  1,4--5
3796e5c31af7Sopenharmony_ci			 *  |\   |
3797e5c31af7Sopenharmony_ci			 *  | \  |
3798e5c31af7Sopenharmony_ci			 *  2----3,6
3799e5c31af7Sopenharmony_ci			 */
3800e5c31af7Sopenharmony_ci			const float v1_4[] = {
3801e5c31af7Sopenharmony_ci				quad_start_x_ss, quad_start_y_ss, 0.0f, /* z */
3802e5c31af7Sopenharmony_ci				1.0f,									/* w */
3803e5c31af7Sopenharmony_ci			};
3804e5c31af7Sopenharmony_ci			const float v2[] = {
3805e5c31af7Sopenharmony_ci				quad_start_x_ss, quad_end_y_ss, 0.0f, /* z */
3806e5c31af7Sopenharmony_ci				1.0f								  /* w */
3807e5c31af7Sopenharmony_ci			};
3808e5c31af7Sopenharmony_ci			const float v3_6[] = {
3809e5c31af7Sopenharmony_ci				quad_end_x_ss, quad_end_y_ss, 0.0f, /* z */
3810e5c31af7Sopenharmony_ci				1.0f								/* w */
3811e5c31af7Sopenharmony_ci			};
3812e5c31af7Sopenharmony_ci			const float v5[] = {
3813e5c31af7Sopenharmony_ci				quad_end_x_ss, quad_start_y_ss, 0.0f, /* z */
3814e5c31af7Sopenharmony_ci				1.0f								  /* w */
3815e5c31af7Sopenharmony_ci			};
3816e5c31af7Sopenharmony_ci
3817e5c31af7Sopenharmony_ci			memcpy(data_traveller_ptr, v1_4, sizeof(v1_4));
3818e5c31af7Sopenharmony_ci			data_traveller_ptr += sizeof(v1_4);
3819e5c31af7Sopenharmony_ci
3820e5c31af7Sopenharmony_ci			memcpy(data_traveller_ptr, v2, sizeof(v2));
3821e5c31af7Sopenharmony_ci			data_traveller_ptr += sizeof(v2);
3822e5c31af7Sopenharmony_ci
3823e5c31af7Sopenharmony_ci			memcpy(data_traveller_ptr, v3_6, sizeof(v3_6));
3824e5c31af7Sopenharmony_ci			data_traveller_ptr += sizeof(v3_6);
3825e5c31af7Sopenharmony_ci
3826e5c31af7Sopenharmony_ci			memcpy(data_traveller_ptr, v1_4, sizeof(v1_4));
3827e5c31af7Sopenharmony_ci			data_traveller_ptr += sizeof(v1_4);
3828e5c31af7Sopenharmony_ci
3829e5c31af7Sopenharmony_ci			memcpy(data_traveller_ptr, v5, sizeof(v5));
3830e5c31af7Sopenharmony_ci			data_traveller_ptr += sizeof(v5);
3831e5c31af7Sopenharmony_ci
3832e5c31af7Sopenharmony_ci			memcpy(data_traveller_ptr, v3_6, sizeof(v3_6));
3833e5c31af7Sopenharmony_ci			data_traveller_ptr += sizeof(v3_6);
3834e5c31af7Sopenharmony_ci		} /* for (all quads in X) */
3835e5c31af7Sopenharmony_ci	}	 /* for (all quads in Y) */
3836e5c31af7Sopenharmony_ci
3837e5c31af7Sopenharmony_ci	/* Set up index data if needed */
3838e5c31af7Sopenharmony_ci	if (m_ibo_usage != IBO_USAGE_NONE)
3839e5c31af7Sopenharmony_ci	{
3840e5c31af7Sopenharmony_ci		*out_ibo_data_offset = static_cast<unsigned int>(data_traveller_ptr - *out_data);
3841e5c31af7Sopenharmony_ci
3842e5c31af7Sopenharmony_ci		for (int index = m_n_vertices_to_draw - 1; index >= 0; --index)
3843e5c31af7Sopenharmony_ci		{
3844e5c31af7Sopenharmony_ci			*(unsigned short*)data_traveller_ptr = (unsigned short)index;
3845e5c31af7Sopenharmony_ci			data_traveller_ptr += sizeof(unsigned short);
3846e5c31af7Sopenharmony_ci		} /* for (all index values) */
3847e5c31af7Sopenharmony_ci	}	 /* if (m_use_ibo) */
3848e5c31af7Sopenharmony_ci	else
3849e5c31af7Sopenharmony_ci	{
3850e5c31af7Sopenharmony_ci		*out_ibo_data_offset = 0;
3851e5c31af7Sopenharmony_ci	}
3852e5c31af7Sopenharmony_ci
3853e5c31af7Sopenharmony_ci	/* Set up color data if needed */
3854e5c31af7Sopenharmony_ci	if (m_use_color_data)
3855e5c31af7Sopenharmony_ci	{
3856e5c31af7Sopenharmony_ci		*out_color_data_offset = static_cast<unsigned int>(data_traveller_ptr - *out_data);
3857e5c31af7Sopenharmony_ci
3858e5c31af7Sopenharmony_ci		for (unsigned int n_quad = 0; n_quad < m_n_quads_x * m_n_quads_y; ++n_quad)
3859e5c31af7Sopenharmony_ci		{
3860e5c31af7Sopenharmony_ci			/* Use magic formulas to generate a color data set for the quads. The data
3861e5c31af7Sopenharmony_ci			 * needs to be duplicated for 6 vertices forming a single quad. */
3862e5c31af7Sopenharmony_ci			for (unsigned int n_vertex = 0; n_vertex < 6; ++n_vertex)
3863e5c31af7Sopenharmony_ci			{
3864e5c31af7Sopenharmony_ci				/* Red */
3865e5c31af7Sopenharmony_ci				*data_traveller_ptr = static_cast<unsigned char>(n_quad % 256); //((n_quad + 15) * 14) % 256;
3866e5c31af7Sopenharmony_ci				data_traveller_ptr++;
3867e5c31af7Sopenharmony_ci
3868e5c31af7Sopenharmony_ci				/* Green */
3869e5c31af7Sopenharmony_ci				*data_traveller_ptr = static_cast<unsigned char>(((n_quad + 32) * 7) % 255);
3870e5c31af7Sopenharmony_ci				data_traveller_ptr++;
3871e5c31af7Sopenharmony_ci
3872e5c31af7Sopenharmony_ci				/* Blue */
3873e5c31af7Sopenharmony_ci				*data_traveller_ptr = static_cast<unsigned char>(((n_quad + 7) * 53) % 255);
3874e5c31af7Sopenharmony_ci				data_traveller_ptr++;
3875e5c31af7Sopenharmony_ci
3876e5c31af7Sopenharmony_ci				/* Alpha */
3877e5c31af7Sopenharmony_ci				*data_traveller_ptr = static_cast<unsigned char>(((n_quad + 13) * 3) % 255);
3878e5c31af7Sopenharmony_ci				data_traveller_ptr++;
3879e5c31af7Sopenharmony_ci			}
3880e5c31af7Sopenharmony_ci		} /* for (all quads) */
3881e5c31af7Sopenharmony_ci	}
3882e5c31af7Sopenharmony_ci	else
3883e5c31af7Sopenharmony_ci	{
3884e5c31af7Sopenharmony_ci		*out_color_data_offset = 0;
3885e5c31af7Sopenharmony_ci	}
3886e5c31af7Sopenharmony_ci}
3887e5c31af7Sopenharmony_ci
3888e5c31af7Sopenharmony_ci/** Releases all GL objects used across all test case iterations.
3889e5c31af7Sopenharmony_ci *
3890e5c31af7Sopenharmony_ci *  Called once during BufferStorage test run-time.
3891e5c31af7Sopenharmony_ci */
3892e5c31af7Sopenharmony_civoid QuadsBufferStorageTestCase::deinitTestCaseGlobal()
3893e5c31af7Sopenharmony_ci{
3894e5c31af7Sopenharmony_ci	if (m_data != DE_NULL)
3895e5c31af7Sopenharmony_ci	{
3896e5c31af7Sopenharmony_ci		delete[] m_data;
3897e5c31af7Sopenharmony_ci
3898e5c31af7Sopenharmony_ci		m_data = DE_NULL;
3899e5c31af7Sopenharmony_ci	}
3900e5c31af7Sopenharmony_ci
3901e5c31af7Sopenharmony_ci	if (m_fbo != 0)
3902e5c31af7Sopenharmony_ci	{
3903e5c31af7Sopenharmony_ci		m_gl.deleteFramebuffers(1, &m_fbo);
3904e5c31af7Sopenharmony_ci
3905e5c31af7Sopenharmony_ci		m_fbo = 0;
3906e5c31af7Sopenharmony_ci	}
3907e5c31af7Sopenharmony_ci
3908e5c31af7Sopenharmony_ci	if (m_helper_bo != 0)
3909e5c31af7Sopenharmony_ci	{
3910e5c31af7Sopenharmony_ci		m_gl.deleteBuffers(1, &m_helper_bo);
3911e5c31af7Sopenharmony_ci
3912e5c31af7Sopenharmony_ci		m_helper_bo = 0;
3913e5c31af7Sopenharmony_ci	}
3914e5c31af7Sopenharmony_ci
3915e5c31af7Sopenharmony_ci	if (m_po != 0)
3916e5c31af7Sopenharmony_ci	{
3917e5c31af7Sopenharmony_ci		m_gl.deleteProgram(m_po);
3918e5c31af7Sopenharmony_ci
3919e5c31af7Sopenharmony_ci		m_po = 0;
3920e5c31af7Sopenharmony_ci	}
3921e5c31af7Sopenharmony_ci
3922e5c31af7Sopenharmony_ci	if (m_to != 0)
3923e5c31af7Sopenharmony_ci	{
3924e5c31af7Sopenharmony_ci		m_gl.deleteTextures(1, &m_to);
3925e5c31af7Sopenharmony_ci
3926e5c31af7Sopenharmony_ci		m_to = 0;
3927e5c31af7Sopenharmony_ci	}
3928e5c31af7Sopenharmony_ci
3929e5c31af7Sopenharmony_ci	if (m_vao != 0)
3930e5c31af7Sopenharmony_ci	{
3931e5c31af7Sopenharmony_ci		m_gl.deleteVertexArrays(1, &m_vao);
3932e5c31af7Sopenharmony_ci
3933e5c31af7Sopenharmony_ci		m_vao = 0;
3934e5c31af7Sopenharmony_ci	}
3935e5c31af7Sopenharmony_ci}
3936e5c31af7Sopenharmony_ci
3937e5c31af7Sopenharmony_ci/** Releases temporary GL objects, created specifically for one test case iteration. */
3938e5c31af7Sopenharmony_civoid QuadsBufferStorageTestCase::deinitTestCaseIteration()
3939e5c31af7Sopenharmony_ci{
3940e5c31af7Sopenharmony_ci	/* If the test executed successfully, all pages should've been released by now.
3941e5c31af7Sopenharmony_ci	 * However, if it failed, it's a good idea to de-commit them at this point.
3942e5c31af7Sopenharmony_ci	 * Redundant calls are fine spec-wise, too. */
3943e5c31af7Sopenharmony_ci	if (m_sparse_bo != 0)
3944e5c31af7Sopenharmony_ci	{
3945e5c31af7Sopenharmony_ci		m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
3946e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
3947e5c31af7Sopenharmony_ci
3948e5c31af7Sopenharmony_ci		m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,			 /* offset */
3949e5c31af7Sopenharmony_ci									 m_data_size_rounded, GL_FALSE); /* commit */
3950e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
3951e5c31af7Sopenharmony_ci
3952e5c31af7Sopenharmony_ci		m_sparse_bo = 0;
3953e5c31af7Sopenharmony_ci	}
3954e5c31af7Sopenharmony_ci}
3955e5c31af7Sopenharmony_ci
3956e5c31af7Sopenharmony_ci/** Executes a single test iteration. The BufferStorage test will call this method
3957e5c31af7Sopenharmony_ci *  numerously during its life-time, testing various valid flag combinations applied
3958e5c31af7Sopenharmony_ci *  to the tested sparse buffer object at glBufferStorage() call time.
3959e5c31af7Sopenharmony_ci *
3960e5c31af7Sopenharmony_ci *  @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage()
3961e5c31af7Sopenharmony_ci *                                 call to set up the sparse buffer's storage.
3962e5c31af7Sopenharmony_ci *
3963e5c31af7Sopenharmony_ci *  @return true if the test case executed correctly, false otherwise.
3964e5c31af7Sopenharmony_ci */
3965e5c31af7Sopenharmony_cibool QuadsBufferStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags)
3966e5c31af7Sopenharmony_ci{
3967e5c31af7Sopenharmony_ci	bool result = true;
3968e5c31af7Sopenharmony_ci
3969e5c31af7Sopenharmony_ci	m_gl.viewport(0, /* x */
3970e5c31af7Sopenharmony_ci				  0, /* y */
3971e5c31af7Sopenharmony_ci				  m_to_width, m_to_height);
3972e5c31af7Sopenharmony_ci
3973e5c31af7Sopenharmony_ci	m_gl.useProgram(m_po);
3974e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() call failed.");
3975e5c31af7Sopenharmony_ci
3976e5c31af7Sopenharmony_ci	m_gl.clearColor(0.0f,  /* red */
3977e5c31af7Sopenharmony_ci					0.0f,  /* green */
3978e5c31af7Sopenharmony_ci					0.0f,  /* blue */
3979e5c31af7Sopenharmony_ci					0.0f); /* alpha */
3980e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glClearColor() call failed.");
3981e5c31af7Sopenharmony_ci
3982e5c31af7Sopenharmony_ci	/* Render the quads.
3983e5c31af7Sopenharmony_ci	 *
3984e5c31af7Sopenharmony_ci	 * Run in two iterations:
3985e5c31af7Sopenharmony_ci	 *
3986e5c31af7Sopenharmony_ci	 * a) Iteration 1 performs the draw call with the VBO & IBO pages committed
3987e5c31af7Sopenharmony_ci	 * b) Iteration 2 performs the draw call with the VBO & IBO pages without any
3988e5c31af7Sopenharmony_ci	 *    physical backing.
3989e5c31af7Sopenharmony_ci	 **/
3990e5c31af7Sopenharmony_ci	for (unsigned int n_iteration = 0; n_iteration < 2; ++n_iteration)
3991e5c31af7Sopenharmony_ci	{
3992e5c31af7Sopenharmony_ci		initSparseBO((n_iteration == 0), /* decommit pages after upload */
3993e5c31af7Sopenharmony_ci					 (sparse_bo_storage_flags & GL_DYNAMIC_STORAGE_BIT) != 0);
3994e5c31af7Sopenharmony_ci
3995e5c31af7Sopenharmony_ci		m_gl.clear(GL_COLOR_BUFFER_BIT);
3996e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glClear() call failed.");
3997e5c31af7Sopenharmony_ci
3998e5c31af7Sopenharmony_ci		switch (m_ibo_usage)
3999e5c31af7Sopenharmony_ci		{
4000e5c31af7Sopenharmony_ci		case IBO_USAGE_NONE:
4001e5c31af7Sopenharmony_ci		{
4002e5c31af7Sopenharmony_ci			m_gl.drawArrays(GL_TRIANGLES, 0, /* first */
4003e5c31af7Sopenharmony_ci							m_n_vertices_to_draw);
4004e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArrays() call failed.");
4005e5c31af7Sopenharmony_ci
4006e5c31af7Sopenharmony_ci			break;
4007e5c31af7Sopenharmony_ci		}
4008e5c31af7Sopenharmony_ci
4009e5c31af7Sopenharmony_ci		case IBO_USAGE_INDEXED_DRAW_CALL:
4010e5c31af7Sopenharmony_ci		{
4011e5c31af7Sopenharmony_ci			m_gl.drawElements(GL_TRIANGLES, m_n_vertices_to_draw, GL_UNSIGNED_SHORT,
4012e5c31af7Sopenharmony_ci							  (glw::GLvoid*)(intptr_t)m_ibo_data_offset);
4013e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawElements() call failed.");
4014e5c31af7Sopenharmony_ci
4015e5c31af7Sopenharmony_ci			break;
4016e5c31af7Sopenharmony_ci		}
4017e5c31af7Sopenharmony_ci
4018e5c31af7Sopenharmony_ci		case IBO_USAGE_INDEXED_RANGED_DRAW_CALL:
4019e5c31af7Sopenharmony_ci		{
4020e5c31af7Sopenharmony_ci			m_gl.drawRangeElements(GL_TRIANGLES, 0,		 /* start */
4021e5c31af7Sopenharmony_ci								   m_n_vertices_to_draw, /* end */
4022e5c31af7Sopenharmony_ci								   m_n_vertices_to_draw, /* count */
4023e5c31af7Sopenharmony_ci								   GL_UNSIGNED_SHORT, (glw::GLvoid*)(intptr_t)m_ibo_data_offset);
4024e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawRangeElements() call failed.");
4025e5c31af7Sopenharmony_ci
4026e5c31af7Sopenharmony_ci			break;
4027e5c31af7Sopenharmony_ci		}
4028e5c31af7Sopenharmony_ci
4029e5c31af7Sopenharmony_ci		default:
4030e5c31af7Sopenharmony_ci		{
4031e5c31af7Sopenharmony_ci			TCU_FAIL("Unrecognized IBO usage value");
4032e5c31af7Sopenharmony_ci		}
4033e5c31af7Sopenharmony_ci		} /* switch (m_ibo_usage) */
4034e5c31af7Sopenharmony_ci
4035e5c31af7Sopenharmony_ci		/* Retrieve the rendered output */
4036e5c31af7Sopenharmony_ci		unsigned char* read_data = new unsigned char[m_to_width * m_to_height * sizeof(char) * 4 /* rgba */];
4037e5c31af7Sopenharmony_ci
4038e5c31af7Sopenharmony_ci		m_gl.readPixels(0, /* x */
4039e5c31af7Sopenharmony_ci						0, /* y */
4040e5c31af7Sopenharmony_ci						m_to_width, m_to_height, GL_RGBA, GL_UNSIGNED_BYTE, read_data);
4041e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glReadPixels() call failed.");
4042e5c31af7Sopenharmony_ci
4043e5c31af7Sopenharmony_ci		/* IF the data pages have been committed by the time the draw call was made, validate the data.
4044e5c31af7Sopenharmony_ci		 *
4045e5c31af7Sopenharmony_ci		 * For each quad region (be it filled or not), check the center and make sure the retrieved
4046e5c31af7Sopenharmony_ci		 * color corresponds to the expected value.
4047e5c31af7Sopenharmony_ci		 */
4048e5c31af7Sopenharmony_ci		if (m_pages_committed)
4049e5c31af7Sopenharmony_ci		{
4050e5c31af7Sopenharmony_ci			for (unsigned int n_quad_region_y = 0; n_quad_region_y < m_n_quads_y * 2; /* quad + empty "delta" region */
4051e5c31af7Sopenharmony_ci				 ++n_quad_region_y)
4052e5c31af7Sopenharmony_ci			{
4053e5c31af7Sopenharmony_ci				for (unsigned int n_quad_region_x = 0; n_quad_region_x < m_n_quads_x * 2; ++n_quad_region_x)
4054e5c31af7Sopenharmony_ci				{
4055e5c31af7Sopenharmony_ci					/* Determine the expected texel color */
4056e5c31af7Sopenharmony_ci					unsigned char expected_color[4];
4057e5c31af7Sopenharmony_ci					unsigned char found_color[4];
4058e5c31af7Sopenharmony_ci					bool		  is_delta_region = (n_quad_region_x % 2) != 0 || (n_quad_region_y % 2) != 0;
4059e5c31af7Sopenharmony_ci
4060e5c31af7Sopenharmony_ci					if (is_delta_region)
4061e5c31af7Sopenharmony_ci					{
4062e5c31af7Sopenharmony_ci						memset(expected_color, 0, sizeof(expected_color));
4063e5c31af7Sopenharmony_ci					} /* if (is_delta_region) */
4064e5c31af7Sopenharmony_ci					else
4065e5c31af7Sopenharmony_ci					{
4066e5c31af7Sopenharmony_ci						if (m_use_color_data)
4067e5c31af7Sopenharmony_ci						{
4068e5c31af7Sopenharmony_ci							const unsigned int   n_quad_x = n_quad_region_x / 2;
4069e5c31af7Sopenharmony_ci							const unsigned int   n_quad_y = n_quad_region_y / 2;
4070e5c31af7Sopenharmony_ci							const unsigned char* data_ptr =
4071e5c31af7Sopenharmony_ci								m_data + m_color_data_offset +
4072e5c31af7Sopenharmony_ci								(n_quad_y * m_n_quads_x + n_quad_x) * 4 /* rgba */ * 6; /* vertices */
4073e5c31af7Sopenharmony_ci
4074e5c31af7Sopenharmony_ci							memcpy(expected_color, data_ptr, sizeof(expected_color));
4075e5c31af7Sopenharmony_ci						} /* if (m_use_color_data) */
4076e5c31af7Sopenharmony_ci						else
4077e5c31af7Sopenharmony_ci						{
4078e5c31af7Sopenharmony_ci							memset(expected_color, 255, sizeof(expected_color));
4079e5c31af7Sopenharmony_ci						}
4080e5c31af7Sopenharmony_ci					}
4081e5c31af7Sopenharmony_ci
4082e5c31af7Sopenharmony_ci					/* Do we have a match? */
4083e5c31af7Sopenharmony_ci					DE_ASSERT(m_n_quad_height == m_n_quad_delta_y);
4084e5c31af7Sopenharmony_ci					DE_ASSERT(m_n_quad_width == m_n_quad_delta_x);
4085e5c31af7Sopenharmony_ci
4086e5c31af7Sopenharmony_ci					const unsigned int sample_texel_x = m_n_quad_delta_x * n_quad_region_x;
4087e5c31af7Sopenharmony_ci					const unsigned int sample_texel_y = m_n_quad_delta_y * n_quad_region_y;
4088e5c31af7Sopenharmony_ci
4089e5c31af7Sopenharmony_ci					memcpy(found_color, read_data + (sample_texel_y * m_to_width + sample_texel_x) * 4, /* rgba */
4090e5c31af7Sopenharmony_ci						   sizeof(found_color));
4091e5c31af7Sopenharmony_ci
4092e5c31af7Sopenharmony_ci					if (memcmp(expected_color, found_color, sizeof(expected_color)) != 0)
4093e5c31af7Sopenharmony_ci					{
4094e5c31af7Sopenharmony_ci						m_testCtx.getLog() << tcu::TestLog::Message << "Invalid color found at "
4095e5c31af7Sopenharmony_ci																	   "("
4096e5c31af7Sopenharmony_ci										   << sample_texel_x << ", " << sample_texel_y << "): "
4097e5c31af7Sopenharmony_ci																						  "Expected color:"
4098e5c31af7Sopenharmony_ci																						  "("
4099e5c31af7Sopenharmony_ci										   << (int)expected_color[0] << ", " << (int)expected_color[1] << ", "
4100e5c31af7Sopenharmony_ci										   << (int)expected_color[2] << ", " << (int)expected_color[3] << "), "
4101e5c31af7Sopenharmony_ci																										  "Found:"
4102e5c31af7Sopenharmony_ci																										  "("
4103e5c31af7Sopenharmony_ci										   << (int)found_color[0] << ", " << (int)found_color[1] << ", "
4104e5c31af7Sopenharmony_ci										   << (int)found_color[2] << ", " << (int)found_color[3] << "), "
4105e5c31af7Sopenharmony_ci										   << tcu::TestLog::EndMessage;
4106e5c31af7Sopenharmony_ci
4107e5c31af7Sopenharmony_ci						result = false;
4108e5c31af7Sopenharmony_ci						goto end;
4109e5c31af7Sopenharmony_ci					}
4110e5c31af7Sopenharmony_ci				} /* for (all quads in X) */
4111e5c31af7Sopenharmony_ci			}	 /* for (all quads in Y) */
4112e5c31af7Sopenharmony_ci		}		  /* if (m_pages_committed) */
4113e5c31af7Sopenharmony_ci
4114e5c31af7Sopenharmony_ci		delete[] read_data;
4115e5c31af7Sopenharmony_ci		read_data = DE_NULL;
4116e5c31af7Sopenharmony_ci	} /* for (both iterations) */
4117e5c31af7Sopenharmony_ci
4118e5c31af7Sopenharmony_ciend:
4119e5c31af7Sopenharmony_ci	return result;
4120e5c31af7Sopenharmony_ci}
4121e5c31af7Sopenharmony_ci
4122e5c31af7Sopenharmony_ci/** Creates test data and fills the result buffer object (whose ID is stored under m_helper_bo)
4123e5c31af7Sopenharmony_ci *  with the data.
4124e5c31af7Sopenharmony_ci */
4125e5c31af7Sopenharmony_civoid QuadsBufferStorageTestCase::initHelperBO()
4126e5c31af7Sopenharmony_ci{
4127e5c31af7Sopenharmony_ci	DE_ASSERT(m_data == DE_NULL);
4128e5c31af7Sopenharmony_ci	DE_ASSERT(m_helper_bo == 0);
4129e5c31af7Sopenharmony_ci
4130e5c31af7Sopenharmony_ci	createTestData(&m_data, &m_vbo_data_offset, &m_ibo_data_offset, &m_color_data_offset);
4131e5c31af7Sopenharmony_ci
4132e5c31af7Sopenharmony_ci	m_gl.genBuffers(1, &m_helper_bo);
4133e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
4134e5c31af7Sopenharmony_ci
4135e5c31af7Sopenharmony_ci	m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
4136e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
4137e5c31af7Sopenharmony_ci
4138e5c31af7Sopenharmony_ci	m_gl.bufferStorage(GL_COPY_READ_BUFFER, m_data_size, m_data, 0); /* flags */
4139e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed.");
4140e5c31af7Sopenharmony_ci}
4141e5c31af7Sopenharmony_ci
4142e5c31af7Sopenharmony_ci/** Creates test data (if necessary), configures sparse buffer's memory page commitment
4143e5c31af7Sopenharmony_ci *  and uploads the test data to the buffer object. Finally, the method configures the
4144e5c31af7Sopenharmony_ci *  vertex array object, used by ::execute() at the draw call time.
4145e5c31af7Sopenharmony_ci *
4146e5c31af7Sopenharmony_ci *  @param decommit_data_pages_after_upload true to de-commit memory pages requested before
4147e5c31af7Sopenharmony_ci *                                          uploading the vertex/index/color data.
4148e5c31af7Sopenharmony_ci *  @param is_dynamic_storage               true to upload the data via glBufferSubData() call.
4149e5c31af7Sopenharmony_ci *                                          false to use a copy op for the operation.
4150e5c31af7Sopenharmony_ci **/
4151e5c31af7Sopenharmony_civoid QuadsBufferStorageTestCase::initSparseBO(bool decommit_data_pages_after_upload, bool is_dynamic_storage)
4152e5c31af7Sopenharmony_ci{
4153e5c31af7Sopenharmony_ci	/* Set up the vertex buffer object. */
4154e5c31af7Sopenharmony_ci	if (m_data == DE_NULL)
4155e5c31af7Sopenharmony_ci	{
4156e5c31af7Sopenharmony_ci		createTestData(&m_data, &m_vbo_data_offset, &m_ibo_data_offset, &m_color_data_offset);
4157e5c31af7Sopenharmony_ci	}
4158e5c31af7Sopenharmony_ci	else
4159e5c31af7Sopenharmony_ci	{
4160e5c31af7Sopenharmony_ci		/* Quick checks */
4161e5c31af7Sopenharmony_ci		if (m_ibo_usage != IBO_USAGE_NONE)
4162e5c31af7Sopenharmony_ci		{
4163e5c31af7Sopenharmony_ci			DE_ASSERT(m_vbo_data_offset != m_ibo_data_offset);
4164e5c31af7Sopenharmony_ci		}
4165e5c31af7Sopenharmony_ci
4166e5c31af7Sopenharmony_ci		if (m_use_color_data)
4167e5c31af7Sopenharmony_ci		{
4168e5c31af7Sopenharmony_ci			DE_ASSERT(m_vbo_data_offset != m_ibo_data_offset);
4169e5c31af7Sopenharmony_ci			DE_ASSERT(m_ibo_data_offset != m_color_data_offset);
4170e5c31af7Sopenharmony_ci		}
4171e5c31af7Sopenharmony_ci	}
4172e5c31af7Sopenharmony_ci
4173e5c31af7Sopenharmony_ci	/* Commit as many pages as we need to upload the data */
4174e5c31af7Sopenharmony_ci	m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,			/* offset */
4175e5c31af7Sopenharmony_ci								 m_data_size_rounded, GL_TRUE); /* commit */
4176e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
4177e5c31af7Sopenharmony_ci
4178e5c31af7Sopenharmony_ci	m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
4179e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
4180e5c31af7Sopenharmony_ci
4181e5c31af7Sopenharmony_ci	m_pages_committed = true;
4182e5c31af7Sopenharmony_ci
4183e5c31af7Sopenharmony_ci	/* Upload the data */
4184e5c31af7Sopenharmony_ci	if (is_dynamic_storage)
4185e5c31af7Sopenharmony_ci	{
4186e5c31af7Sopenharmony_ci		m_gl.bufferSubData(GL_ARRAY_BUFFER, 0, /* offset */
4187e5c31af7Sopenharmony_ci						   m_data_size, m_data);
4188e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferSubData() call failed.");
4189e5c31af7Sopenharmony_ci	}
4190e5c31af7Sopenharmony_ci	else
4191e5c31af7Sopenharmony_ci	{
4192e5c31af7Sopenharmony_ci		/* Sparse BO cannot be directly uploaded data to. Copy the data from a helper BO */
4193e5c31af7Sopenharmony_ci		m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_ARRAY_BUFFER, 0, /* readOffset */
4194e5c31af7Sopenharmony_ci							   0,										/* writeOffset */
4195e5c31af7Sopenharmony_ci							   m_data_size);
4196e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
4197e5c31af7Sopenharmony_ci	}
4198e5c31af7Sopenharmony_ci
4199e5c31af7Sopenharmony_ci	/* Set the VAO up */
4200e5c31af7Sopenharmony_ci	m_gl.vertexAttribPointer(m_attribute_position_location, 4, /* size */
4201e5c31af7Sopenharmony_ci							 GL_FLOAT, GL_FALSE,			   /* normalized */
4202e5c31af7Sopenharmony_ci							 0,								   /* stride */
4203e5c31af7Sopenharmony_ci							 (glw::GLvoid*)(intptr_t)m_vbo_data_offset);
4204e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glVertexAttribPointer() call failed.");
4205e5c31af7Sopenharmony_ci
4206e5c31af7Sopenharmony_ci	m_gl.enableVertexAttribArray(m_attribute_position_location); /* index */
4207e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glEnableVertexAttribPointer() call failed.");
4208e5c31af7Sopenharmony_ci
4209e5c31af7Sopenharmony_ci	if (m_use_color_data)
4210e5c31af7Sopenharmony_ci	{
4211e5c31af7Sopenharmony_ci		m_gl.vertexAttribPointer(m_attribute_color_location, 4, /* size */
4212e5c31af7Sopenharmony_ci								 GL_UNSIGNED_BYTE, GL_TRUE,		/* normalized */
4213e5c31af7Sopenharmony_ci								 0,								/* stride */
4214e5c31af7Sopenharmony_ci								 (glw::GLvoid*)(intptr_t)m_color_data_offset);
4215e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glVertexAttribPointer() call failed.");
4216e5c31af7Sopenharmony_ci
4217e5c31af7Sopenharmony_ci		m_gl.enableVertexAttribArray(m_attribute_color_location); /* index */
4218e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glEnableVertexAttribPointer() call failed.");
4219e5c31af7Sopenharmony_ci	}
4220e5c31af7Sopenharmony_ci	else
4221e5c31af7Sopenharmony_ci	{
4222e5c31af7Sopenharmony_ci		m_gl.vertexAttrib4f(m_attribute_color_location, 1.0f, 1.0f, 1.0f, 1.0f);
4223e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glVertexAttrib4f() call failed.");
4224e5c31af7Sopenharmony_ci
4225e5c31af7Sopenharmony_ci		m_gl.disableVertexAttribArray(m_attribute_color_location);
4226e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDisableVertexAttribArray() call failed.");
4227e5c31af7Sopenharmony_ci	}
4228e5c31af7Sopenharmony_ci
4229e5c31af7Sopenharmony_ci	if (m_ibo_usage != IBO_USAGE_NONE)
4230e5c31af7Sopenharmony_ci	{
4231e5c31af7Sopenharmony_ci		m_gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_sparse_bo);
4232e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
4233e5c31af7Sopenharmony_ci	} /* if (m_use_ibo) */
4234e5c31af7Sopenharmony_ci
4235e5c31af7Sopenharmony_ci	/* If we were requested to do so, decommit the pages we have just uploaded
4236e5c31af7Sopenharmony_ci	 * the data to.
4237e5c31af7Sopenharmony_ci	 */
4238e5c31af7Sopenharmony_ci	if (decommit_data_pages_after_upload)
4239e5c31af7Sopenharmony_ci	{
4240e5c31af7Sopenharmony_ci		m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,			 /* offset */
4241e5c31af7Sopenharmony_ci									 m_data_size_rounded, GL_FALSE); /* commit */
4242e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
4243e5c31af7Sopenharmony_ci
4244e5c31af7Sopenharmony_ci		m_pages_committed = false;
4245e5c31af7Sopenharmony_ci	} /* if (decommit_data_pages_after_upload) */
4246e5c31af7Sopenharmony_ci}
4247e5c31af7Sopenharmony_ci
4248e5c31af7Sopenharmony_ci/** Initializes GL objects used across all test case iterations.
4249e5c31af7Sopenharmony_ci *
4250e5c31af7Sopenharmony_ci *  Called once during BufferStorage test run-time.
4251e5c31af7Sopenharmony_ci */
4252e5c31af7Sopenharmony_cibool QuadsBufferStorageTestCase::initTestCaseGlobal()
4253e5c31af7Sopenharmony_ci{
4254e5c31af7Sopenharmony_ci	bool result = true;
4255e5c31af7Sopenharmony_ci
4256e5c31af7Sopenharmony_ci	/* Set up the texture object */
4257e5c31af7Sopenharmony_ci	DE_ASSERT(m_to == 0);
4258e5c31af7Sopenharmony_ci
4259e5c31af7Sopenharmony_ci	m_gl.genTextures(1, &m_to);
4260e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenTextures() call failed.");
4261e5c31af7Sopenharmony_ci
4262e5c31af7Sopenharmony_ci	m_gl.bindTexture(GL_TEXTURE_2D, m_to);
4263e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindTexture() call failed.");
4264e5c31af7Sopenharmony_ci
4265e5c31af7Sopenharmony_ci	m_gl.texStorage2D(GL_TEXTURE_2D, 1, /* levels */
4266e5c31af7Sopenharmony_ci					  GL_RGBA8, m_to_width, m_to_height);
4267e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glTexStorage2D() call failed.");
4268e5c31af7Sopenharmony_ci
4269e5c31af7Sopenharmony_ci	/* Set up the framebuffer object */
4270e5c31af7Sopenharmony_ci	DE_ASSERT(m_fbo == 0);
4271e5c31af7Sopenharmony_ci
4272e5c31af7Sopenharmony_ci	m_gl.genFramebuffers(1, &m_fbo);
4273e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenFramebuffers() call failed.");
4274e5c31af7Sopenharmony_ci
4275e5c31af7Sopenharmony_ci	m_gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
4276e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindFramebuffer() call failed.");
4277e5c31af7Sopenharmony_ci
4278e5c31af7Sopenharmony_ci	m_gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_to, 0); /* level */
4279e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glFramebufferTexture2D() call failed.");
4280e5c31af7Sopenharmony_ci
4281e5c31af7Sopenharmony_ci	/* Set up the vertex array object */
4282e5c31af7Sopenharmony_ci	DE_ASSERT(m_vao == 0);
4283e5c31af7Sopenharmony_ci
4284e5c31af7Sopenharmony_ci	m_gl.genVertexArrays(1, &m_vao);
4285e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenVertexArrays() call failed.");
4286e5c31af7Sopenharmony_ci
4287e5c31af7Sopenharmony_ci	m_gl.bindVertexArray(m_vao);
4288e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindVertexArray() call failed.");
4289e5c31af7Sopenharmony_ci
4290e5c31af7Sopenharmony_ci	/* Init a helper BO */
4291e5c31af7Sopenharmony_ci	initHelperBO();
4292e5c31af7Sopenharmony_ci
4293e5c31af7Sopenharmony_ci	/* Set up the program object */
4294e5c31af7Sopenharmony_ci	const char* fs_body = "#version 430 core\n"
4295e5c31af7Sopenharmony_ci						  "\n"
4296e5c31af7Sopenharmony_ci						  "flat in  vec4 fs_color;\n"
4297e5c31af7Sopenharmony_ci						  "     out vec4 color;\n"
4298e5c31af7Sopenharmony_ci						  "\n"
4299e5c31af7Sopenharmony_ci						  "void main()\n"
4300e5c31af7Sopenharmony_ci						  "{\n"
4301e5c31af7Sopenharmony_ci						  "    color = fs_color;\n"
4302e5c31af7Sopenharmony_ci						  "}\n";
4303e5c31af7Sopenharmony_ci
4304e5c31af7Sopenharmony_ci	const char* vs_body = "#version 430 core\n"
4305e5c31af7Sopenharmony_ci						  "\n"
4306e5c31af7Sopenharmony_ci						  "in vec4 color;\n"
4307e5c31af7Sopenharmony_ci						  "in vec4 position;\n"
4308e5c31af7Sopenharmony_ci						  "\n"
4309e5c31af7Sopenharmony_ci						  "flat out vec4 fs_color;\n"
4310e5c31af7Sopenharmony_ci						  "\n"
4311e5c31af7Sopenharmony_ci						  "void main()\n"
4312e5c31af7Sopenharmony_ci						  "{\n"
4313e5c31af7Sopenharmony_ci						  "    fs_color    = color;\n"
4314e5c31af7Sopenharmony_ci						  "    gl_Position = position;\n"
4315e5c31af7Sopenharmony_ci						  "}\n";
4316e5c31af7Sopenharmony_ci
4317e5c31af7Sopenharmony_ci	const unsigned int attribute_locations[] = { m_attribute_color_location, m_attribute_position_location };
4318e5c31af7Sopenharmony_ci	const char*		   attribute_names[]	 = { "color", "position" };
4319e5c31af7Sopenharmony_ci	const unsigned int n_attributes			 = sizeof(attribute_locations) / sizeof(attribute_locations[0]);
4320e5c31af7Sopenharmony_ci
4321e5c31af7Sopenharmony_ci	DE_ASSERT(m_po == 0);
4322e5c31af7Sopenharmony_ci
4323e5c31af7Sopenharmony_ci	m_po = SparseBufferTestUtilities::createProgram(m_gl, &fs_body, 1, /* n_fs_body_parts */
4324e5c31af7Sopenharmony_ci													&vs_body, 1, attribute_names, attribute_locations,
4325e5c31af7Sopenharmony_ci													n_attributes); /* n_vs_body_parts */
4326e5c31af7Sopenharmony_ci
4327e5c31af7Sopenharmony_ci	if (m_po == 0)
4328e5c31af7Sopenharmony_ci	{
4329e5c31af7Sopenharmony_ci		result = false;
4330e5c31af7Sopenharmony_ci
4331e5c31af7Sopenharmony_ci		goto end;
4332e5c31af7Sopenharmony_ci	}
4333e5c31af7Sopenharmony_ci
4334e5c31af7Sopenharmony_ciend:
4335e5c31af7Sopenharmony_ci	return result;
4336e5c31af7Sopenharmony_ci}
4337e5c31af7Sopenharmony_ci
4338e5c31af7Sopenharmony_ci/** Initializes GL objects which are needed for a single test case iteration.
4339e5c31af7Sopenharmony_ci *
4340e5c31af7Sopenharmony_ci *  deinitTestCaseIteration() will be called after the test case is executed in ::execute()
4341e5c31af7Sopenharmony_ci *  to release these objects.
4342e5c31af7Sopenharmony_ci **/
4343e5c31af7Sopenharmony_cibool QuadsBufferStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo)
4344e5c31af7Sopenharmony_ci{
4345e5c31af7Sopenharmony_ci	bool result = true;
4346e5c31af7Sopenharmony_ci
4347e5c31af7Sopenharmony_ci	/* Cache the BO id, if not cached already */
4348e5c31af7Sopenharmony_ci	DE_ASSERT(m_sparse_bo == 0 || m_sparse_bo == sparse_bo);
4349e5c31af7Sopenharmony_ci
4350e5c31af7Sopenharmony_ci	m_sparse_bo = sparse_bo;
4351e5c31af7Sopenharmony_ci
4352e5c31af7Sopenharmony_ci	return result;
4353e5c31af7Sopenharmony_ci}
4354e5c31af7Sopenharmony_ci
4355e5c31af7Sopenharmony_ci/** Constructor.
4356e5c31af7Sopenharmony_ci *
4357e5c31af7Sopenharmony_ci *  @param gl                         GL entry-points container
4358e5c31af7Sopenharmony_ci *  @param testContext                CTS test context
4359e5c31af7Sopenharmony_ci *  @param page_size                  Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query.
4360e5c31af7Sopenharmony_ci *  @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point.
4361e5c31af7Sopenharmony_ci */
4362e5c31af7Sopenharmony_ciQueryBufferStorageTestCase::QueryBufferStorageTestCase(const glw::Functions& gl, tcu::TestContext& testContext,
4363e5c31af7Sopenharmony_ci													   glw::GLint page_size)
4364e5c31af7Sopenharmony_ci	: m_gl(gl)
4365e5c31af7Sopenharmony_ci	, m_helper_bo(0)
4366e5c31af7Sopenharmony_ci	, m_n_triangles(15)
4367e5c31af7Sopenharmony_ci	, m_page_size(page_size)
4368e5c31af7Sopenharmony_ci	, m_po(0)
4369e5c31af7Sopenharmony_ci	, m_qo(0)
4370e5c31af7Sopenharmony_ci	, m_sparse_bo(0)
4371e5c31af7Sopenharmony_ci	, m_sparse_bo_size(0)
4372e5c31af7Sopenharmony_ci	, m_sparse_bo_size_rounded(0)
4373e5c31af7Sopenharmony_ci	, m_testCtx(testContext)
4374e5c31af7Sopenharmony_ci	, m_vao(0)
4375e5c31af7Sopenharmony_ci{
4376e5c31af7Sopenharmony_ci	/* Left blank on purpose */
4377e5c31af7Sopenharmony_ci}
4378e5c31af7Sopenharmony_ci
4379e5c31af7Sopenharmony_ci/** Releases all GL objects used across all test case iterations.
4380e5c31af7Sopenharmony_ci *
4381e5c31af7Sopenharmony_ci *  Called once during BufferStorage test run-time.
4382e5c31af7Sopenharmony_ci */
4383e5c31af7Sopenharmony_civoid QueryBufferStorageTestCase::deinitTestCaseGlobal()
4384e5c31af7Sopenharmony_ci{
4385e5c31af7Sopenharmony_ci	if (m_helper_bo != 0)
4386e5c31af7Sopenharmony_ci	{
4387e5c31af7Sopenharmony_ci		m_gl.deleteBuffers(1, &m_helper_bo);
4388e5c31af7Sopenharmony_ci
4389e5c31af7Sopenharmony_ci		m_helper_bo = 0;
4390e5c31af7Sopenharmony_ci	}
4391e5c31af7Sopenharmony_ci
4392e5c31af7Sopenharmony_ci	if (m_po != 0)
4393e5c31af7Sopenharmony_ci	{
4394e5c31af7Sopenharmony_ci		m_gl.deleteProgram(m_po);
4395e5c31af7Sopenharmony_ci
4396e5c31af7Sopenharmony_ci		m_po = 0;
4397e5c31af7Sopenharmony_ci	}
4398e5c31af7Sopenharmony_ci
4399e5c31af7Sopenharmony_ci	if (m_qo != 0)
4400e5c31af7Sopenharmony_ci	{
4401e5c31af7Sopenharmony_ci		m_gl.deleteQueries(1, &m_qo);
4402e5c31af7Sopenharmony_ci
4403e5c31af7Sopenharmony_ci		m_qo = 0;
4404e5c31af7Sopenharmony_ci	}
4405e5c31af7Sopenharmony_ci
4406e5c31af7Sopenharmony_ci	if (m_vao != 0)
4407e5c31af7Sopenharmony_ci	{
4408e5c31af7Sopenharmony_ci		m_gl.deleteVertexArrays(1, &m_vao);
4409e5c31af7Sopenharmony_ci
4410e5c31af7Sopenharmony_ci		m_vao = 0;
4411e5c31af7Sopenharmony_ci	}
4412e5c31af7Sopenharmony_ci}
4413e5c31af7Sopenharmony_ci
4414e5c31af7Sopenharmony_ci/** Releases temporary GL objects, created specifically for one test case iteration. */
4415e5c31af7Sopenharmony_civoid QueryBufferStorageTestCase::deinitTestCaseIteration()
4416e5c31af7Sopenharmony_ci{
4417e5c31af7Sopenharmony_ci	if (m_sparse_bo != 0)
4418e5c31af7Sopenharmony_ci	{
4419e5c31af7Sopenharmony_ci		m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
4420e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
4421e5c31af7Sopenharmony_ci
4422e5c31af7Sopenharmony_ci		m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,				  /* offset */
4423e5c31af7Sopenharmony_ci									 m_sparse_bo_size_rounded, GL_FALSE); /* commit */
4424e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
4425e5c31af7Sopenharmony_ci
4426e5c31af7Sopenharmony_ci		m_sparse_bo = 0;
4427e5c31af7Sopenharmony_ci	}
4428e5c31af7Sopenharmony_ci}
4429e5c31af7Sopenharmony_ci
4430e5c31af7Sopenharmony_ci/** Executes a single test iteration. The BufferStorage test will call this method
4431e5c31af7Sopenharmony_ci *  numerously during its life-time, testing various valid flag combinations applied
4432e5c31af7Sopenharmony_ci *  to the tested sparse buffer object at glBufferStorage() call time.
4433e5c31af7Sopenharmony_ci *
4434e5c31af7Sopenharmony_ci *  @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage()
4435e5c31af7Sopenharmony_ci *                                 call to set up the sparse buffer's storage.
4436e5c31af7Sopenharmony_ci *
4437e5c31af7Sopenharmony_ci *  @return true if the test case executed correctly, false otherwise.
4438e5c31af7Sopenharmony_ci */
4439e5c31af7Sopenharmony_cibool QueryBufferStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags)
4440e5c31af7Sopenharmony_ci{
4441e5c31af7Sopenharmony_ci	(void)sparse_bo_storage_flags;
4442e5c31af7Sopenharmony_ci	static const unsigned char data_r8_zero = 0;
4443e5c31af7Sopenharmony_ci	bool					   result		= true;
4444e5c31af7Sopenharmony_ci
4445e5c31af7Sopenharmony_ci	m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_sparse_bo);
4446e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
4447e5c31af7Sopenharmony_ci
4448e5c31af7Sopenharmony_ci	m_gl.useProgram(m_po);
4449e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() call failed.");
4450e5c31af7Sopenharmony_ci
4451e5c31af7Sopenharmony_ci	/* Run two separate iterations:
4452e5c31af7Sopenharmony_ci	 *
4453e5c31af7Sopenharmony_ci	 * a) The page holding the query result value is committed.
4454e5c31af7Sopenharmony_ci	 * b) The page is not committed.
4455e5c31af7Sopenharmony_ci	 */
4456e5c31af7Sopenharmony_ci	for (unsigned int n_iteration = 0; n_iteration < 2; ++n_iteration)
4457e5c31af7Sopenharmony_ci	{
4458e5c31af7Sopenharmony_ci		const bool should_commit_page = (n_iteration == 0);
4459e5c31af7Sopenharmony_ci
4460e5c31af7Sopenharmony_ci		/* Set up the memory page commitment */
4461e5c31af7Sopenharmony_ci		m_gl.bufferPageCommitmentARB(GL_QUERY_BUFFER, 0, /* offset */
4462e5c31af7Sopenharmony_ci									 m_sparse_bo_size_rounded, should_commit_page ? GL_TRUE : GL_FALSE);
4463e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
4464e5c31af7Sopenharmony_ci
4465e5c31af7Sopenharmony_ci		/* Run the draw call */
4466e5c31af7Sopenharmony_ci		m_gl.beginQuery(GL_PRIMITIVES_GENERATED, m_qo);
4467e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBeginQuery() call failed.");
4468e5c31af7Sopenharmony_ci
4469e5c31af7Sopenharmony_ci		m_gl.drawArrays(GL_TRIANGLES, 0, /* first */
4470e5c31af7Sopenharmony_ci						m_n_triangles * 3);
4471e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArrays() call failed.");
4472e5c31af7Sopenharmony_ci
4473e5c31af7Sopenharmony_ci		m_gl.endQuery(GL_PRIMITIVES_GENERATED);
4474e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glEndQuery() call failed.");
4475e5c31af7Sopenharmony_ci
4476e5c31af7Sopenharmony_ci		/* Copy the query result to the sparse buffer */
4477e5c31af7Sopenharmony_ci		for (unsigned int n_getter_call = 0; n_getter_call < 4; ++n_getter_call)
4478e5c31af7Sopenharmony_ci		{
4479e5c31af7Sopenharmony_ci			glw::GLsizei result_n_bytes;
4480e5c31af7Sopenharmony_ci
4481e5c31af7Sopenharmony_ci			switch (n_getter_call)
4482e5c31af7Sopenharmony_ci			{
4483e5c31af7Sopenharmony_ci			case 0:
4484e5c31af7Sopenharmony_ci			{
4485e5c31af7Sopenharmony_ci				result_n_bytes = sizeof(glw::GLint);
4486e5c31af7Sopenharmony_ci				m_gl.getQueryObjectiv(m_qo, GL_QUERY_RESULT, (glw::GLint*)0); /* params */
4487e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetQueryObjectiv() call failed.");
4488e5c31af7Sopenharmony_ci
4489e5c31af7Sopenharmony_ci				break;
4490e5c31af7Sopenharmony_ci			}
4491e5c31af7Sopenharmony_ci
4492e5c31af7Sopenharmony_ci			case 1:
4493e5c31af7Sopenharmony_ci			{
4494e5c31af7Sopenharmony_ci				result_n_bytes = sizeof(glw::GLint);
4495e5c31af7Sopenharmony_ci				m_gl.getQueryObjectuiv(m_qo, GL_QUERY_RESULT, (glw::GLuint*)0); /* params */
4496e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetQueryObjectuiv() call failed.");
4497e5c31af7Sopenharmony_ci
4498e5c31af7Sopenharmony_ci				break;
4499e5c31af7Sopenharmony_ci			}
4500e5c31af7Sopenharmony_ci
4501e5c31af7Sopenharmony_ci			case 2:
4502e5c31af7Sopenharmony_ci			{
4503e5c31af7Sopenharmony_ci				result_n_bytes = sizeof(glw::GLint64);
4504e5c31af7Sopenharmony_ci				m_gl.getQueryObjecti64v(m_qo, GL_QUERY_RESULT, (glw::GLint64*)0);
4505e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetQueryObjecti64v() call failed.");
4506e5c31af7Sopenharmony_ci
4507e5c31af7Sopenharmony_ci				break;
4508e5c31af7Sopenharmony_ci			}
4509e5c31af7Sopenharmony_ci
4510e5c31af7Sopenharmony_ci			case 3:
4511e5c31af7Sopenharmony_ci			{
4512e5c31af7Sopenharmony_ci				result_n_bytes = sizeof(glw::GLint64);
4513e5c31af7Sopenharmony_ci				m_gl.getQueryObjectui64v(m_qo, GL_QUERY_RESULT, (glw::GLuint64*)0);
4514e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetQueryObjectui64v() call failed.");
4515e5c31af7Sopenharmony_ci
4516e5c31af7Sopenharmony_ci				break;
4517e5c31af7Sopenharmony_ci			}
4518e5c31af7Sopenharmony_ci
4519e5c31af7Sopenharmony_ci			default:
4520e5c31af7Sopenharmony_ci			{
4521e5c31af7Sopenharmony_ci				TCU_FAIL("Invalid getter call type");
4522e5c31af7Sopenharmony_ci			}
4523e5c31af7Sopenharmony_ci			} /* switch (n_getter_call) */
4524e5c31af7Sopenharmony_ci
4525e5c31af7Sopenharmony_ci			/* Verify the query result */
4526e5c31af7Sopenharmony_ci			if (should_commit_page)
4527e5c31af7Sopenharmony_ci			{
4528e5c31af7Sopenharmony_ci				const glw::GLint64* result_ptr = NULL;
4529e5c31af7Sopenharmony_ci
4530e5c31af7Sopenharmony_ci				m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_helper_bo);
4531e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
4532e5c31af7Sopenharmony_ci
4533e5c31af7Sopenharmony_ci				m_gl.clearBufferData(GL_COPY_WRITE_BUFFER, GL_R8, GL_RED, GL_UNSIGNED_BYTE, &data_r8_zero);
4534e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glClearBufferData() call failed.");
4535e5c31af7Sopenharmony_ci
4536e5c31af7Sopenharmony_ci				m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, /* readOffset */
4537e5c31af7Sopenharmony_ci									   0,											 /* writeOffset */
4538e5c31af7Sopenharmony_ci									   result_n_bytes);
4539e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
4540e5c31af7Sopenharmony_ci
4541e5c31af7Sopenharmony_ci				result_ptr = (const glw::GLint64*)m_gl.mapBuffer(GL_COPY_WRITE_BUFFER, GL_READ_ONLY);
4542e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMapBuffer() call failed.");
4543e5c31af7Sopenharmony_ci
4544e5c31af7Sopenharmony_ci				if (*result_ptr != m_n_triangles)
4545e5c31af7Sopenharmony_ci				{
4546e5c31af7Sopenharmony_ci					m_testCtx.getLog() << tcu::TestLog::Message
4547e5c31af7Sopenharmony_ci									   << "Invalid query result stored in a sparse buffer. Found: "
4548e5c31af7Sopenharmony_ci										  "["
4549e5c31af7Sopenharmony_ci									   << *result_ptr << "]"
4550e5c31af7Sopenharmony_ci														 ", expected: "
4551e5c31af7Sopenharmony_ci														 "["
4552e5c31af7Sopenharmony_ci									   << m_n_triangles << "]" << tcu::TestLog::EndMessage;
4553e5c31af7Sopenharmony_ci
4554e5c31af7Sopenharmony_ci					result = false;
4555e5c31af7Sopenharmony_ci				}
4556e5c31af7Sopenharmony_ci
4557e5c31af7Sopenharmony_ci				m_gl.unmapBuffer(GL_COPY_WRITE_BUFFER);
4558e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUnmapBuffer() call failed.");
4559e5c31af7Sopenharmony_ci			} /* for (all query getter call types) */
4560e5c31af7Sopenharmony_ci		}	 /* if (should_commit_page) */
4561e5c31af7Sopenharmony_ci	}		  /* for (both iterations) */
4562e5c31af7Sopenharmony_ci
4563e5c31af7Sopenharmony_ci	return result;
4564e5c31af7Sopenharmony_ci}
4565e5c31af7Sopenharmony_ci
4566e5c31af7Sopenharmony_ci/** Initializes GL objects used across all test case iterations.
4567e5c31af7Sopenharmony_ci *
4568e5c31af7Sopenharmony_ci *  Called once during BufferStorage test run-time.
4569e5c31af7Sopenharmony_ci */
4570e5c31af7Sopenharmony_cibool QueryBufferStorageTestCase::initTestCaseGlobal()
4571e5c31af7Sopenharmony_ci{
4572e5c31af7Sopenharmony_ci	/* Determine sparse buffer storage size */
4573e5c31af7Sopenharmony_ci	m_sparse_bo_size		 = sizeof(glw::GLuint64);
4574e5c31af7Sopenharmony_ci	m_sparse_bo_size_rounded = SparseBufferTestUtilities::alignOffset(m_sparse_bo_size, m_page_size);
4575e5c31af7Sopenharmony_ci
4576e5c31af7Sopenharmony_ci	/* Set up the test program object */
4577e5c31af7Sopenharmony_ci	static const char* vs_body = "#version 140\n"
4578e5c31af7Sopenharmony_ci								 "\n"
4579e5c31af7Sopenharmony_ci								 "void main()\n"
4580e5c31af7Sopenharmony_ci								 "{\n"
4581e5c31af7Sopenharmony_ci								 "    gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n"
4582e5c31af7Sopenharmony_ci								 "}\n";
4583e5c31af7Sopenharmony_ci
4584e5c31af7Sopenharmony_ci	m_po = SparseBufferTestUtilities::createProgram(m_gl, DE_NULL, /* fs_body_parts */
4585e5c31af7Sopenharmony_ci													0,			   /* n_fs_body_parts */
4586e5c31af7Sopenharmony_ci													&vs_body, 1,   /* n_vs_body_parts */
4587e5c31af7Sopenharmony_ci													DE_NULL,	   /* attribute_names */
4588e5c31af7Sopenharmony_ci													DE_NULL,	   /* attribute_locations */
4589e5c31af7Sopenharmony_ci													0);			   /* n_attribute_locations */
4590e5c31af7Sopenharmony_ci
4591e5c31af7Sopenharmony_ci	if (m_po == 0)
4592e5c31af7Sopenharmony_ci	{
4593e5c31af7Sopenharmony_ci		TCU_FAIL("Test program linking failure");
4594e5c31af7Sopenharmony_ci	}
4595e5c31af7Sopenharmony_ci
4596e5c31af7Sopenharmony_ci	/* Set up the helper buffer object */
4597e5c31af7Sopenharmony_ci	m_gl.genBuffers(1, &m_helper_bo);
4598e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
4599e5c31af7Sopenharmony_ci
4600e5c31af7Sopenharmony_ci	m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_helper_bo);
4601e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
4602e5c31af7Sopenharmony_ci
4603e5c31af7Sopenharmony_ci	m_gl.bufferStorage(GL_COPY_WRITE_BUFFER, sizeof(glw::GLint64), DE_NULL, /* data */
4604e5c31af7Sopenharmony_ci					   GL_MAP_READ_BIT);
4605e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed.");
4606e5c31af7Sopenharmony_ci
4607e5c31af7Sopenharmony_ci	/* Set up the test query object */
4608e5c31af7Sopenharmony_ci	m_gl.genQueries(1, &m_qo);
4609e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenQueries() call failed.");
4610e5c31af7Sopenharmony_ci
4611e5c31af7Sopenharmony_ci	/* Set up the VAO */
4612e5c31af7Sopenharmony_ci	m_gl.genVertexArrays(1, &m_vao);
4613e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenVertexArrays() call failed.");
4614e5c31af7Sopenharmony_ci
4615e5c31af7Sopenharmony_ci	m_gl.bindVertexArray(m_vao);
4616e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindVertexArray() call failed.");
4617e5c31af7Sopenharmony_ci
4618e5c31af7Sopenharmony_ci	return true;
4619e5c31af7Sopenharmony_ci}
4620e5c31af7Sopenharmony_ci
4621e5c31af7Sopenharmony_ci/** Initializes GL objects which are needed for a single test case iteration.
4622e5c31af7Sopenharmony_ci *
4623e5c31af7Sopenharmony_ci *  deinitTestCaseIteration() will be called after the test case is executed in ::execute()
4624e5c31af7Sopenharmony_ci *  to release these objects.
4625e5c31af7Sopenharmony_ci **/
4626e5c31af7Sopenharmony_cibool QueryBufferStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo)
4627e5c31af7Sopenharmony_ci{
4628e5c31af7Sopenharmony_ci	bool result = true;
4629e5c31af7Sopenharmony_ci
4630e5c31af7Sopenharmony_ci	/* Cache the BO id, if not cached already */
4631e5c31af7Sopenharmony_ci	DE_ASSERT(m_sparse_bo == 0 || m_sparse_bo == sparse_bo);
4632e5c31af7Sopenharmony_ci
4633e5c31af7Sopenharmony_ci	m_sparse_bo = sparse_bo;
4634e5c31af7Sopenharmony_ci
4635e5c31af7Sopenharmony_ci	/* Set up the sparse buffer. */
4636e5c31af7Sopenharmony_ci	m_gl.bindBuffer(GL_QUERY_BUFFER, m_sparse_bo);
4637e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
4638e5c31af7Sopenharmony_ci
4639e5c31af7Sopenharmony_ci	return result;
4640e5c31af7Sopenharmony_ci}
4641e5c31af7Sopenharmony_ci
4642e5c31af7Sopenharmony_ci/** Constructor.
4643e5c31af7Sopenharmony_ci *
4644e5c31af7Sopenharmony_ci *  @param gl                         GL entry-points container
4645e5c31af7Sopenharmony_ci *  @param testContext                CTS test context
4646e5c31af7Sopenharmony_ci *  @param page_size                  Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query.
4647e5c31af7Sopenharmony_ci *  @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point.
4648e5c31af7Sopenharmony_ci */
4649e5c31af7Sopenharmony_ciSSBOStorageTestCase::SSBOStorageTestCase(const glw::Functions& gl, tcu::TestContext& testContext, glw::GLint page_size)
4650e5c31af7Sopenharmony_ci	: m_gl(gl)
4651e5c31af7Sopenharmony_ci	, m_helper_bo(0)
4652e5c31af7Sopenharmony_ci	, m_page_size(page_size)
4653e5c31af7Sopenharmony_ci	, m_po(0)
4654e5c31af7Sopenharmony_ci	, m_po_local_wg_size(1024)
4655e5c31af7Sopenharmony_ci	, m_result_bo(0)
4656e5c31af7Sopenharmony_ci	, m_sparse_bo(0)
4657e5c31af7Sopenharmony_ci	, m_sparse_bo_size(0)
4658e5c31af7Sopenharmony_ci	, m_sparse_bo_size_rounded(0)
4659e5c31af7Sopenharmony_ci	, m_ssbo_data(DE_NULL)
4660e5c31af7Sopenharmony_ci	, m_testCtx(testContext)
4661e5c31af7Sopenharmony_ci{
4662e5c31af7Sopenharmony_ci	/* min max for SSBO size from GL_ARB_shader_storage_buffer_object is 16mb;
4663e5c31af7Sopenharmony_ci	 *
4664e5c31af7Sopenharmony_ci	 * The specified amount of space lets the test write as many
4665e5c31af7Sopenharmony_ci	 * ints as it's possible, with an assertion that our CS
4666e5c31af7Sopenharmony_ci	 * uses a std140 layout and the SSBO only contains an unsized array.
4667e5c31af7Sopenharmony_ci	 *
4668e5c31af7Sopenharmony_ci	 * NOTE: 16777216 % 1024 = 0, which is awesome because we can hardcode the
4669e5c31af7Sopenharmony_ci	 *       local workgroup size directly in the CS.
4670e5c31af7Sopenharmony_ci	 */
4671e5c31af7Sopenharmony_ci	m_sparse_bo_size		 = (16777216 / (sizeof(int) * 4) /* std140 */) * (sizeof(int) * 4);
4672e5c31af7Sopenharmony_ci	m_sparse_bo_size_rounded = SparseBufferTestUtilities::alignOffset(m_sparse_bo_size, m_page_size);
4673e5c31af7Sopenharmony_ci}
4674e5c31af7Sopenharmony_ci
4675e5c31af7Sopenharmony_ci/** Releases all GL objects used across all test case iterations.
4676e5c31af7Sopenharmony_ci *
4677e5c31af7Sopenharmony_ci *  Called once during BufferStorage test run-time.
4678e5c31af7Sopenharmony_ci */
4679e5c31af7Sopenharmony_civoid SSBOStorageTestCase::deinitTestCaseGlobal()
4680e5c31af7Sopenharmony_ci{
4681e5c31af7Sopenharmony_ci	if (m_helper_bo != 0)
4682e5c31af7Sopenharmony_ci	{
4683e5c31af7Sopenharmony_ci		m_gl.deleteBuffers(1, &m_helper_bo);
4684e5c31af7Sopenharmony_ci
4685e5c31af7Sopenharmony_ci		m_helper_bo = 0;
4686e5c31af7Sopenharmony_ci	}
4687e5c31af7Sopenharmony_ci
4688e5c31af7Sopenharmony_ci	if (m_po != 0)
4689e5c31af7Sopenharmony_ci	{
4690e5c31af7Sopenharmony_ci		m_gl.deleteProgram(m_po);
4691e5c31af7Sopenharmony_ci
4692e5c31af7Sopenharmony_ci		m_po = 0;
4693e5c31af7Sopenharmony_ci	}
4694e5c31af7Sopenharmony_ci
4695e5c31af7Sopenharmony_ci	if (m_result_bo != 0)
4696e5c31af7Sopenharmony_ci	{
4697e5c31af7Sopenharmony_ci		m_gl.deleteBuffers(1, &m_result_bo);
4698e5c31af7Sopenharmony_ci
4699e5c31af7Sopenharmony_ci		m_result_bo = 0;
4700e5c31af7Sopenharmony_ci	}
4701e5c31af7Sopenharmony_ci
4702e5c31af7Sopenharmony_ci	if (m_ssbo_data != DE_NULL)
4703e5c31af7Sopenharmony_ci	{
4704e5c31af7Sopenharmony_ci		delete[] m_ssbo_data;
4705e5c31af7Sopenharmony_ci
4706e5c31af7Sopenharmony_ci		m_ssbo_data = DE_NULL;
4707e5c31af7Sopenharmony_ci	}
4708e5c31af7Sopenharmony_ci}
4709e5c31af7Sopenharmony_ci
4710e5c31af7Sopenharmony_ci/** Releases temporary GL objects, created specifically for one test case iteration. */
4711e5c31af7Sopenharmony_civoid SSBOStorageTestCase::deinitTestCaseIteration()
4712e5c31af7Sopenharmony_ci{
4713e5c31af7Sopenharmony_ci	if (m_sparse_bo != 0)
4714e5c31af7Sopenharmony_ci	{
4715e5c31af7Sopenharmony_ci		m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
4716e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
4717e5c31af7Sopenharmony_ci
4718e5c31af7Sopenharmony_ci		m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,				  /* offset */
4719e5c31af7Sopenharmony_ci									 m_sparse_bo_size_rounded, GL_FALSE); /* commit */
4720e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
4721e5c31af7Sopenharmony_ci
4722e5c31af7Sopenharmony_ci		m_sparse_bo = 0;
4723e5c31af7Sopenharmony_ci	}
4724e5c31af7Sopenharmony_ci}
4725e5c31af7Sopenharmony_ci
4726e5c31af7Sopenharmony_ci/** Executes a single test iteration. The BufferStorage test will call this method
4727e5c31af7Sopenharmony_ci *  numerously during its life-time, testing various valid flag combinations applied
4728e5c31af7Sopenharmony_ci *  to the tested sparse buffer object at glBufferStorage() call time.
4729e5c31af7Sopenharmony_ci *
4730e5c31af7Sopenharmony_ci *  @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage()
4731e5c31af7Sopenharmony_ci *                                 call to set up the sparse buffer's storage.
4732e5c31af7Sopenharmony_ci *
4733e5c31af7Sopenharmony_ci *  @return true if the test case executed correctly, false otherwise.
4734e5c31af7Sopenharmony_ci */
4735e5c31af7Sopenharmony_cibool SSBOStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags)
4736e5c31af7Sopenharmony_ci{
4737e5c31af7Sopenharmony_ci	(void)sparse_bo_storage_flags;
4738e5c31af7Sopenharmony_ci	bool result = true;
4739e5c31af7Sopenharmony_ci
4740e5c31af7Sopenharmony_ci	/* Bind the program object */
4741e5c31af7Sopenharmony_ci	m_gl.useProgram(m_po);
4742e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() call failed.");
4743e5c31af7Sopenharmony_ci
4744e5c31af7Sopenharmony_ci	/* Set up shader storage buffer bindings */
4745e5c31af7Sopenharmony_ci	m_gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, m_sparse_bo);
4746e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
4747e5c31af7Sopenharmony_ci
4748e5c31af7Sopenharmony_ci	m_gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, /* index */
4749e5c31af7Sopenharmony_ci						m_sparse_bo);
4750e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBufferBase() call failed.");
4751e5c31af7Sopenharmony_ci
4752e5c31af7Sopenharmony_ci	/* Run the test in three iterations:
4753e5c31af7Sopenharmony_ci	 *
4754e5c31af7Sopenharmony_ci	 * a) All required pages are committed.
4755e5c31af7Sopenharmony_ci	 * b) Only half of the pages are committed (in a zig-zag layout)
4756e5c31af7Sopenharmony_ci	 * c) None of the pages are committed.
4757e5c31af7Sopenharmony_ci	 */
4758e5c31af7Sopenharmony_ci	for (unsigned int n_iteration = 0; n_iteration < 3; ++n_iteration)
4759e5c31af7Sopenharmony_ci	{
4760e5c31af7Sopenharmony_ci		bool result_local = true;
4761e5c31af7Sopenharmony_ci
4762e5c31af7Sopenharmony_ci		/* Set up the shader storage buffer object's memory backing */
4763e5c31af7Sopenharmony_ci		const bool   is_zigzag_ssbo			  = (n_iteration == 1);
4764e5c31af7Sopenharmony_ci		unsigned int ssbo_commit_size		  = 0;
4765e5c31af7Sopenharmony_ci		unsigned int ssbo_commit_start_offset = 0;
4766e5c31af7Sopenharmony_ci
4767e5c31af7Sopenharmony_ci		switch (n_iteration)
4768e5c31af7Sopenharmony_ci		{
4769e5c31af7Sopenharmony_ci		case 0:
4770e5c31af7Sopenharmony_ci		case 1:
4771e5c31af7Sopenharmony_ci		{
4772e5c31af7Sopenharmony_ci			ssbo_commit_size		 = m_sparse_bo_size_rounded;
4773e5c31af7Sopenharmony_ci			ssbo_commit_start_offset = 0;
4774e5c31af7Sopenharmony_ci
4775e5c31af7Sopenharmony_ci			if (is_zigzag_ssbo)
4776e5c31af7Sopenharmony_ci			{
4777e5c31af7Sopenharmony_ci				const unsigned int n_pages = ssbo_commit_size / m_page_size;
4778e5c31af7Sopenharmony_ci
4779e5c31af7Sopenharmony_ci				for (unsigned int n_page = 0; n_page < n_pages; n_page += 2)
4780e5c31af7Sopenharmony_ci				{
4781e5c31af7Sopenharmony_ci					m_gl.bufferPageCommitmentARB(GL_SHADER_STORAGE_BUFFER, m_page_size * n_page, /* offset */
4782e5c31af7Sopenharmony_ci												 m_page_size,									 /* size */
4783e5c31af7Sopenharmony_ci												 GL_TRUE);										 /* commit */
4784e5c31af7Sopenharmony_ci				} /* for (all memory pages) */
4785e5c31af7Sopenharmony_ci			}
4786e5c31af7Sopenharmony_ci			else
4787e5c31af7Sopenharmony_ci			{
4788e5c31af7Sopenharmony_ci				m_gl.bufferPageCommitmentARB(GL_SHADER_STORAGE_BUFFER, 0, /* offset */
4789e5c31af7Sopenharmony_ci											 ssbo_commit_size, GL_TRUE);  /* commit */
4790e5c31af7Sopenharmony_ci			}
4791e5c31af7Sopenharmony_ci
4792e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call(s) failed.");
4793e5c31af7Sopenharmony_ci
4794e5c31af7Sopenharmony_ci			break;
4795e5c31af7Sopenharmony_ci		}
4796e5c31af7Sopenharmony_ci
4797e5c31af7Sopenharmony_ci		case 2:
4798e5c31af7Sopenharmony_ci		{
4799e5c31af7Sopenharmony_ci			/* Use no physical memory backing */
4800e5c31af7Sopenharmony_ci			break;
4801e5c31af7Sopenharmony_ci		}
4802e5c31af7Sopenharmony_ci
4803e5c31af7Sopenharmony_ci		default:
4804e5c31af7Sopenharmony_ci		{
4805e5c31af7Sopenharmony_ci			TCU_FAIL("Unrecognized iteration index");
4806e5c31af7Sopenharmony_ci		}
4807e5c31af7Sopenharmony_ci		} /* switch (n_iteration) */
4808e5c31af7Sopenharmony_ci
4809e5c31af7Sopenharmony_ci		/* Set up bindings for the copy op */
4810e5c31af7Sopenharmony_ci		m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
4811e5c31af7Sopenharmony_ci		m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_sparse_bo);
4812e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call(s) failed.");
4813e5c31af7Sopenharmony_ci
4814e5c31af7Sopenharmony_ci		/* Set up the sparse buffer's data storage */
4815e5c31af7Sopenharmony_ci		m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, /* readOffset */
4816e5c31af7Sopenharmony_ci							   0,											 /* writeOffset */
4817e5c31af7Sopenharmony_ci							   m_sparse_bo_size);
4818e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
4819e5c31af7Sopenharmony_ci
4820e5c31af7Sopenharmony_ci		/* Run the compute program */
4821e5c31af7Sopenharmony_ci		DE_ASSERT((m_sparse_bo_size % m_po_local_wg_size) == 0);
4822e5c31af7Sopenharmony_ci
4823e5c31af7Sopenharmony_ci		m_gl.dispatchCompute(m_sparse_bo_size / m_po_local_wg_size, 1, /* num_groups_y */
4824e5c31af7Sopenharmony_ci							 1);									   /* num_groups_z */
4825e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDispatchCompute() call failed.");
4826e5c31af7Sopenharmony_ci
4827e5c31af7Sopenharmony_ci		/* Flush the caches */
4828e5c31af7Sopenharmony_ci		m_gl.memoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
4829e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMemoryBarrier() call failed.");
4830e5c31af7Sopenharmony_ci
4831e5c31af7Sopenharmony_ci		/* Copy SSBO's storage to a mappable result BO */
4832e5c31af7Sopenharmony_ci		m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_sparse_bo);
4833e5c31af7Sopenharmony_ci		m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_result_bo);
4834e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call(s) failed.");
4835e5c31af7Sopenharmony_ci
4836e5c31af7Sopenharmony_ci		m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, /* readOffset */
4837e5c31af7Sopenharmony_ci							   0,											 /* writeOffset */
4838e5c31af7Sopenharmony_ci							   m_sparse_bo_size);
4839e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
4840e5c31af7Sopenharmony_ci
4841e5c31af7Sopenharmony_ci		/* Map the result BO to the process space */
4842e5c31af7Sopenharmony_ci		unsigned int		current_ssbo_offset = 0;
4843e5c31af7Sopenharmony_ci		const unsigned int* ssbo_data_ptr = (const unsigned int*)m_gl.mapBuffer(GL_COPY_WRITE_BUFFER, GL_READ_ONLY);
4844e5c31af7Sopenharmony_ci
4845e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMapBuffer() call failed.");
4846e5c31af7Sopenharmony_ci
4847e5c31af7Sopenharmony_ci		for (unsigned int n_invocation = 0; current_ssbo_offset < m_sparse_bo_size && result_local; ++n_invocation,
4848e5c31af7Sopenharmony_ci						  current_ssbo_offset = static_cast<unsigned int>(current_ssbo_offset +
4849e5c31af7Sopenharmony_ci																		  (sizeof(int) * 4 /* std140 */)))
4850e5c31af7Sopenharmony_ci		{
4851e5c31af7Sopenharmony_ci			const unsigned int n_page = current_ssbo_offset / m_page_size;
4852e5c31af7Sopenharmony_ci
4853e5c31af7Sopenharmony_ci			if ((is_zigzag_ssbo && (n_page % 2) == 0) ||
4854e5c31af7Sopenharmony_ci				(!is_zigzag_ssbo && (current_ssbo_offset >= ssbo_commit_start_offset &&
4855e5c31af7Sopenharmony_ci									 current_ssbo_offset < (ssbo_commit_start_offset + ssbo_commit_size))))
4856e5c31af7Sopenharmony_ci			{
4857e5c31af7Sopenharmony_ci				if (ssbo_data_ptr[n_invocation * 4] != (n_invocation + 1))
4858e5c31af7Sopenharmony_ci				{
4859e5c31af7Sopenharmony_ci					m_testCtx.getLog() << tcu::TestLog::Message << "Value written to the SSBO at byte "
4860e5c31af7Sopenharmony_ci																   "["
4861e5c31af7Sopenharmony_ci									   << (sizeof(int) * n_invocation) << "]"
4862e5c31af7Sopenharmony_ci																		  " is invalid. Found:"
4863e5c31af7Sopenharmony_ci									   << "[" << ssbo_data_ptr[n_invocation * 4] << "]"
4864e5c31af7Sopenharmony_ci																					", expected:"
4865e5c31af7Sopenharmony_ci									   << "[" << (n_invocation + 1) << "]" << tcu::TestLog::EndMessage;
4866e5c31af7Sopenharmony_ci
4867e5c31af7Sopenharmony_ci					result_local = false;
4868e5c31af7Sopenharmony_ci				}
4869e5c31af7Sopenharmony_ci			} /* if (ssbo_data_ptr[n_texel] != 1) */
4870e5c31af7Sopenharmony_ci		}	 /* for (all result values) */
4871e5c31af7Sopenharmony_ci
4872e5c31af7Sopenharmony_ci		result &= result_local;
4873e5c31af7Sopenharmony_ci
4874e5c31af7Sopenharmony_ci		m_gl.unmapBuffer(GL_COPY_WRITE_BUFFER);
4875e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUnmapBuffer() call failed.");
4876e5c31af7Sopenharmony_ci
4877e5c31af7Sopenharmony_ci		/* Remove the physical backing from the sparse buffer  */
4878e5c31af7Sopenharmony_ci		m_gl.bufferPageCommitmentARB(GL_SHADER_STORAGE_BUFFER, 0,		  /* offset */
4879e5c31af7Sopenharmony_ci									 m_sparse_bo_size_rounded, GL_FALSE); /* commit */
4880e5c31af7Sopenharmony_ci
4881e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
4882e5c31af7Sopenharmony_ci	} /* for (three iterations) */
4883e5c31af7Sopenharmony_ci
4884e5c31af7Sopenharmony_ci	return result;
4885e5c31af7Sopenharmony_ci}
4886e5c31af7Sopenharmony_ci
4887e5c31af7Sopenharmony_ci/** Initializes GL objects used across all test case iterations.
4888e5c31af7Sopenharmony_ci *
4889e5c31af7Sopenharmony_ci *  Called once during BufferStorage test run-time.
4890e5c31af7Sopenharmony_ci */
4891e5c31af7Sopenharmony_cibool SSBOStorageTestCase::initTestCaseGlobal()
4892e5c31af7Sopenharmony_ci{
4893e5c31af7Sopenharmony_ci	/* Set up the test program */
4894e5c31af7Sopenharmony_ci	static const char* cs_body =
4895e5c31af7Sopenharmony_ci		"#version 430 core\n"
4896e5c31af7Sopenharmony_ci		"\n"
4897e5c31af7Sopenharmony_ci		"layout(local_size_x = 1024) in;\n"
4898e5c31af7Sopenharmony_ci		"\n"
4899e5c31af7Sopenharmony_ci		"layout(std140, binding = 0) buffer data\n"
4900e5c31af7Sopenharmony_ci		"{\n"
4901e5c31af7Sopenharmony_ci		"    restrict uint io_values[];\n"
4902e5c31af7Sopenharmony_ci		"};\n"
4903e5c31af7Sopenharmony_ci		"\n"
4904e5c31af7Sopenharmony_ci		"void main()\n"
4905e5c31af7Sopenharmony_ci		"{\n"
4906e5c31af7Sopenharmony_ci		"    uint value_index = gl_GlobalInvocationID.x;\n"
4907e5c31af7Sopenharmony_ci		"    uint new_value   = (io_values[value_index] == value_index) ? (value_index + 1u) : value_index;\n"
4908e5c31af7Sopenharmony_ci		"\n"
4909e5c31af7Sopenharmony_ci		"    io_values[value_index] = new_value;\n"
4910e5c31af7Sopenharmony_ci		"}\n";
4911e5c31af7Sopenharmony_ci
4912e5c31af7Sopenharmony_ci	m_po = SparseBufferTestUtilities::createComputeProgram(m_gl, &cs_body, 1); /* n_cs_body_parts */
4913e5c31af7Sopenharmony_ci
4914e5c31af7Sopenharmony_ci	/* Set up a data buffer we will use to initialize the SSBO with default data.
4915e5c31af7Sopenharmony_ci	 *
4916e5c31af7Sopenharmony_ci	 * CS uses a std140 layout for the SSBO, so we need to add the additional padding.
4917e5c31af7Sopenharmony_ci	 */
4918e5c31af7Sopenharmony_ci	DE_ASSERT((m_sparse_bo_size) != 0);
4919e5c31af7Sopenharmony_ci	DE_ASSERT((m_sparse_bo_size % (sizeof(int) * 4)) == 0);
4920e5c31af7Sopenharmony_ci	DE_ASSERT((m_sparse_bo_size % 1024) == 0);
4921e5c31af7Sopenharmony_ci
4922e5c31af7Sopenharmony_ci	m_ssbo_data = new unsigned int[m_sparse_bo_size / sizeof(int)];
4923e5c31af7Sopenharmony_ci
4924e5c31af7Sopenharmony_ci	memset(m_ssbo_data, 0, m_sparse_bo_size);
4925e5c31af7Sopenharmony_ci
4926e5c31af7Sopenharmony_ci	for (unsigned int index = 0; index < m_sparse_bo_size / sizeof(int) / 4; ++index)
4927e5c31af7Sopenharmony_ci	{
4928e5c31af7Sopenharmony_ci		/* Mind the std140 rules for arrays of ints */
4929e5c31af7Sopenharmony_ci		m_ssbo_data[4 * index] = index;
4930e5c31af7Sopenharmony_ci	}
4931e5c31af7Sopenharmony_ci
4932e5c31af7Sopenharmony_ci	/* During execution, we will need to use a helper buffer object. The BO will hold
4933e5c31af7Sopenharmony_ci	 * data we will be copying into the sparse buffer object for each iteration.
4934e5c31af7Sopenharmony_ci	 */
4935e5c31af7Sopenharmony_ci	m_gl.genBuffers(1, &m_helper_bo);
4936e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
4937e5c31af7Sopenharmony_ci
4938e5c31af7Sopenharmony_ci	m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
4939e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
4940e5c31af7Sopenharmony_ci
4941e5c31af7Sopenharmony_ci	m_gl.bufferData(GL_COPY_READ_BUFFER, m_sparse_bo_size, m_ssbo_data, GL_STATIC_DRAW);
4942e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferData() call failed.");
4943e5c31af7Sopenharmony_ci
4944e5c31af7Sopenharmony_ci	/* To retrieve the data written to a sparse SSBO, we need to use another
4945e5c31af7Sopenharmony_ci	 * non-sparse helper BO.
4946e5c31af7Sopenharmony_ci	 */
4947e5c31af7Sopenharmony_ci	m_gl.genBuffers(1, &m_result_bo);
4948e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
4949e5c31af7Sopenharmony_ci
4950e5c31af7Sopenharmony_ci	m_gl.bindBuffer(GL_ARRAY_BUFFER, m_result_bo);
4951e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
4952e5c31af7Sopenharmony_ci
4953e5c31af7Sopenharmony_ci	m_gl.bufferData(GL_ARRAY_BUFFER, m_sparse_bo_size, DE_NULL, /* data */
4954e5c31af7Sopenharmony_ci					GL_STATIC_DRAW);
4955e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferData() call failed.");
4956e5c31af7Sopenharmony_ci
4957e5c31af7Sopenharmony_ci	return true;
4958e5c31af7Sopenharmony_ci}
4959e5c31af7Sopenharmony_ci
4960e5c31af7Sopenharmony_ci/** Initializes GL objects which are needed for a single test case iteration.
4961e5c31af7Sopenharmony_ci *
4962e5c31af7Sopenharmony_ci *  deinitTestCaseIteration() will be called after the test case is executed in ::execute()
4963e5c31af7Sopenharmony_ci *  to release these objects.
4964e5c31af7Sopenharmony_ci **/
4965e5c31af7Sopenharmony_cibool SSBOStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo)
4966e5c31af7Sopenharmony_ci{
4967e5c31af7Sopenharmony_ci	bool result = true;
4968e5c31af7Sopenharmony_ci
4969e5c31af7Sopenharmony_ci	/* Cache the BO id, if not cached already */
4970e5c31af7Sopenharmony_ci	DE_ASSERT(m_sparse_bo == 0 || m_sparse_bo == sparse_bo);
4971e5c31af7Sopenharmony_ci
4972e5c31af7Sopenharmony_ci	m_sparse_bo = sparse_bo;
4973e5c31af7Sopenharmony_ci
4974e5c31af7Sopenharmony_ci	return result;
4975e5c31af7Sopenharmony_ci}
4976e5c31af7Sopenharmony_ci
4977e5c31af7Sopenharmony_ci/** Constructor.
4978e5c31af7Sopenharmony_ci *
4979e5c31af7Sopenharmony_ci *  @param gl                         GL entry-points container
4980e5c31af7Sopenharmony_ci *  @param testContext                CTS test context
4981e5c31af7Sopenharmony_ci *  @param page_size                  Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query.
4982e5c31af7Sopenharmony_ci *  @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point.
4983e5c31af7Sopenharmony_ci *  @param all_pages_committed        true to provide memory backing for all memory pages holding data used by the test.
4984e5c31af7Sopenharmony_ci *                                    false to leave some of them uncommitted.
4985e5c31af7Sopenharmony_ci */
4986e5c31af7Sopenharmony_ciTransformFeedbackBufferStorageTestCase::TransformFeedbackBufferStorageTestCase(const glw::Functions& gl,
4987e5c31af7Sopenharmony_ci																			   tcu::TestContext&	 testContext,
4988e5c31af7Sopenharmony_ci																			   glw::GLint			 page_size,
4989e5c31af7Sopenharmony_ci																			   bool all_pages_committed)
4990e5c31af7Sopenharmony_ci	: m_all_pages_committed(all_pages_committed)
4991e5c31af7Sopenharmony_ci	, m_data_bo(0)
4992e5c31af7Sopenharmony_ci	, m_data_bo_index_data_offset(0)
4993e5c31af7Sopenharmony_ci	, m_data_bo_indexed_indirect_arg_offset(0)
4994e5c31af7Sopenharmony_ci	, m_data_bo_indexed_mdi_arg_offset(0)
4995e5c31af7Sopenharmony_ci	, m_data_bo_regular_indirect_arg_offset(0)
4996e5c31af7Sopenharmony_ci	, m_data_bo_regular_mdi_arg_offset(0)
4997e5c31af7Sopenharmony_ci	, m_data_bo_size(0)
4998e5c31af7Sopenharmony_ci	, m_draw_call_baseInstance(1231)
4999e5c31af7Sopenharmony_ci	, m_draw_call_baseVertex(65537)
5000e5c31af7Sopenharmony_ci	, m_draw_call_first(913)
5001e5c31af7Sopenharmony_ci	, m_draw_call_firstIndex(4)
5002e5c31af7Sopenharmony_ci	, m_gl(gl)
5003e5c31af7Sopenharmony_ci	, m_helper_bo(0)
5004e5c31af7Sopenharmony_ci	, m_index_data(DE_NULL)
5005e5c31af7Sopenharmony_ci	, m_index_data_size(0)
5006e5c31af7Sopenharmony_ci	, m_indirect_arg_data(DE_NULL)
5007e5c31af7Sopenharmony_ci	, m_indirect_arg_data_size(0)
5008e5c31af7Sopenharmony_ci	, m_min_memory_page_span(4) /* as per test spec */
5009e5c31af7Sopenharmony_ci	, m_multidrawcall_drawcount(-1)
5010e5c31af7Sopenharmony_ci	, m_multidrawcall_primcount(-1)
5011e5c31af7Sopenharmony_ci	, m_n_instances_to_test(4)
5012e5c31af7Sopenharmony_ci	, m_n_vertices_per_instance(0)
5013e5c31af7Sopenharmony_ci	, m_page_size(page_size)
5014e5c31af7Sopenharmony_ci	, m_po_ia(0)
5015e5c31af7Sopenharmony_ci	, m_po_sa(0)
5016e5c31af7Sopenharmony_ci	, m_result_bo(0)
5017e5c31af7Sopenharmony_ci	, m_result_bo_size(0)
5018e5c31af7Sopenharmony_ci	, m_result_bo_size_rounded(0)
5019e5c31af7Sopenharmony_ci	, m_testCtx(testContext)
5020e5c31af7Sopenharmony_ci	, m_vao(0)
5021e5c31af7Sopenharmony_ci{
5022e5c31af7Sopenharmony_ci	/* Left blank on purpose */
5023e5c31af7Sopenharmony_ci}
5024e5c31af7Sopenharmony_ci
5025e5c31af7Sopenharmony_ci/** Releases all GL objects used across all test case iterations.
5026e5c31af7Sopenharmony_ci *
5027e5c31af7Sopenharmony_ci *  Called once during BufferStorage test run-time.
5028e5c31af7Sopenharmony_ci */
5029e5c31af7Sopenharmony_civoid TransformFeedbackBufferStorageTestCase::deinitTestCaseGlobal()
5030e5c31af7Sopenharmony_ci{
5031e5c31af7Sopenharmony_ci	if (m_data_bo != 0)
5032e5c31af7Sopenharmony_ci	{
5033e5c31af7Sopenharmony_ci		m_gl.deleteBuffers(1, &m_data_bo);
5034e5c31af7Sopenharmony_ci
5035e5c31af7Sopenharmony_ci		m_data_bo = 0;
5036e5c31af7Sopenharmony_ci	}
5037e5c31af7Sopenharmony_ci
5038e5c31af7Sopenharmony_ci	if (m_helper_bo != 0)
5039e5c31af7Sopenharmony_ci	{
5040e5c31af7Sopenharmony_ci		m_gl.deleteBuffers(1, &m_helper_bo);
5041e5c31af7Sopenharmony_ci
5042e5c31af7Sopenharmony_ci		m_helper_bo = 0;
5043e5c31af7Sopenharmony_ci	}
5044e5c31af7Sopenharmony_ci
5045e5c31af7Sopenharmony_ci	if (m_index_data != DE_NULL)
5046e5c31af7Sopenharmony_ci	{
5047e5c31af7Sopenharmony_ci		delete[] m_index_data;
5048e5c31af7Sopenharmony_ci
5049e5c31af7Sopenharmony_ci		m_index_data = DE_NULL;
5050e5c31af7Sopenharmony_ci	}
5051e5c31af7Sopenharmony_ci
5052e5c31af7Sopenharmony_ci	if (m_indirect_arg_data != DE_NULL)
5053e5c31af7Sopenharmony_ci	{
5054e5c31af7Sopenharmony_ci		delete[] m_indirect_arg_data;
5055e5c31af7Sopenharmony_ci
5056e5c31af7Sopenharmony_ci		m_indirect_arg_data = DE_NULL;
5057e5c31af7Sopenharmony_ci	}
5058e5c31af7Sopenharmony_ci
5059e5c31af7Sopenharmony_ci	if (m_po_ia != 0)
5060e5c31af7Sopenharmony_ci	{
5061e5c31af7Sopenharmony_ci		m_gl.deleteProgram(m_po_ia);
5062e5c31af7Sopenharmony_ci
5063e5c31af7Sopenharmony_ci		m_po_ia = 0;
5064e5c31af7Sopenharmony_ci	}
5065e5c31af7Sopenharmony_ci
5066e5c31af7Sopenharmony_ci	if (m_po_sa != 0)
5067e5c31af7Sopenharmony_ci	{
5068e5c31af7Sopenharmony_ci		m_gl.deleteProgram(m_po_sa);
5069e5c31af7Sopenharmony_ci
5070e5c31af7Sopenharmony_ci		m_po_sa = 0;
5071e5c31af7Sopenharmony_ci	}
5072e5c31af7Sopenharmony_ci
5073e5c31af7Sopenharmony_ci	if (m_result_bo != 0)
5074e5c31af7Sopenharmony_ci	{
5075e5c31af7Sopenharmony_ci		m_gl.deleteBuffers(1, &m_result_bo);
5076e5c31af7Sopenharmony_ci
5077e5c31af7Sopenharmony_ci		m_result_bo = 0;
5078e5c31af7Sopenharmony_ci	}
5079e5c31af7Sopenharmony_ci
5080e5c31af7Sopenharmony_ci	if (m_vao != 0)
5081e5c31af7Sopenharmony_ci	{
5082e5c31af7Sopenharmony_ci		m_gl.deleteVertexArrays(1, &m_vao);
5083e5c31af7Sopenharmony_ci
5084e5c31af7Sopenharmony_ci		m_vao = 0;
5085e5c31af7Sopenharmony_ci	}
5086e5c31af7Sopenharmony_ci}
5087e5c31af7Sopenharmony_ci
5088e5c31af7Sopenharmony_ci/** Executes a single test iteration. The BufferStorage test will call this method
5089e5c31af7Sopenharmony_ci *  numerously during its life-time, testing various valid flag combinations applied
5090e5c31af7Sopenharmony_ci *  to the tested sparse buffer object at glBufferStorage() call time.
5091e5c31af7Sopenharmony_ci *
5092e5c31af7Sopenharmony_ci *  @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage()
5093e5c31af7Sopenharmony_ci *                                 call to set up the sparse buffer's storage.
5094e5c31af7Sopenharmony_ci *
5095e5c31af7Sopenharmony_ci *  @return true if the test case executed correctly, false otherwise.
5096e5c31af7Sopenharmony_ci */
5097e5c31af7Sopenharmony_cibool TransformFeedbackBufferStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags)
5098e5c31af7Sopenharmony_ci{
5099e5c31af7Sopenharmony_ci	bool result = true;
5100e5c31af7Sopenharmony_ci
5101e5c31af7Sopenharmony_ci	/* Iterate through two different transform feedback modes we need to test */
5102e5c31af7Sopenharmony_ci	for (unsigned int n_tf_type = 0; n_tf_type < 2; /* interleaved & separate attribs */
5103e5c31af7Sopenharmony_ci		 ++n_tf_type)
5104e5c31af7Sopenharmony_ci	{
5105e5c31af7Sopenharmony_ci		const bool is_ia_iteration = (n_tf_type == 0);
5106e5c31af7Sopenharmony_ci
5107e5c31af7Sopenharmony_ci		/* Bind the test PO to the context */
5108e5c31af7Sopenharmony_ci		m_gl.useProgram(is_ia_iteration ? m_po_ia : m_po_sa);
5109e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() call failed.");
5110e5c31af7Sopenharmony_ci
5111e5c31af7Sopenharmony_ci		/* Set up TF general binding, which is needed for a glClearBufferData() call
5112e5c31af7Sopenharmony_ci		 * we'll be firing shortly.
5113e5c31af7Sopenharmony_ci		 */
5114e5c31af7Sopenharmony_ci		m_gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, /* needed for the subsequent glClearBufferData() call */
5115e5c31af7Sopenharmony_ci						m_result_bo);
5116e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
5117e5c31af7Sopenharmony_ci
5118e5c31af7Sopenharmony_ci		/* Iterate through all draw call types */
5119e5c31af7Sopenharmony_ci		for (unsigned int n_draw_call_type = 0; n_draw_call_type < DRAW_CALL_COUNT; ++n_draw_call_type)
5120e5c31af7Sopenharmony_ci		{
5121e5c31af7Sopenharmony_ci			int				   draw_call_count					= 0; /* != 1 for multi-draw calls only */
5122e5c31af7Sopenharmony_ci			int				   draw_call_first_instance_id[2]   = { -1 };
5123e5c31af7Sopenharmony_ci			int				   draw_call_first_vertex_id[2]		= { -1 };
5124e5c31af7Sopenharmony_ci			int				   draw_call_n_instances[2]			= { 0 };
5125e5c31af7Sopenharmony_ci			int				   draw_call_n_vertices[2]			= { 0 };
5126e5c31af7Sopenharmony_ci			bool			   draw_call_is_vertex_id_ascending = false;
5127e5c31af7Sopenharmony_ci			const _draw_call   draw_call_type					= (_draw_call)n_draw_call_type;
5128e5c31af7Sopenharmony_ci			unsigned int	   n_result_bytes_per_instance[2]   = { 0 };
5129e5c31af7Sopenharmony_ci			const unsigned int n_result_bytes_per_vertex		= sizeof(unsigned int) * 2;
5130e5c31af7Sopenharmony_ci			unsigned int	   n_result_bytes_total				= 0;
5131e5c31af7Sopenharmony_ci			glw::GLuint*	   result_ptr						= DE_NULL;
5132e5c31af7Sopenharmony_ci
5133e5c31af7Sopenharmony_ci			m_gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_data_bo);
5134e5c31af7Sopenharmony_ci			m_gl.bindBuffer(GL_DRAW_INDIRECT_BUFFER, m_data_bo);
5135e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call(s) failed.");
5136e5c31af7Sopenharmony_ci
5137e5c31af7Sopenharmony_ci			/* Commit pages needed to execute transform feed-back */
5138e5c31af7Sopenharmony_ci			if (m_all_pages_committed)
5139e5c31af7Sopenharmony_ci			{
5140e5c31af7Sopenharmony_ci				m_gl.bufferPageCommitmentARB(GL_TRANSFORM_FEEDBACK_BUFFER, 0,	/* offset */
5141e5c31af7Sopenharmony_ci											 m_result_bo_size_rounded, GL_TRUE); /* commit */
5142e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
5143e5c31af7Sopenharmony_ci			}
5144e5c31af7Sopenharmony_ci			else
5145e5c31af7Sopenharmony_ci			{
5146e5c31af7Sopenharmony_ci				for (unsigned int n_page = 0; n_page < m_result_bo_size_rounded / m_page_size; ++n_page)
5147e5c31af7Sopenharmony_ci				{
5148e5c31af7Sopenharmony_ci					m_gl.bufferPageCommitmentARB(GL_TRANSFORM_FEEDBACK_BUFFER, n_page * m_page_size, /* offset */
5149e5c31af7Sopenharmony_ci												 m_page_size,										 /* size   */
5150e5c31af7Sopenharmony_ci												 (n_page % 2 == 0) ? GL_TRUE : GL_FALSE);			 /* commit */
5151e5c31af7Sopenharmony_ci				}
5152e5c31af7Sopenharmony_ci
5153e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
5154e5c31af7Sopenharmony_ci			}
5155e5c31af7Sopenharmony_ci
5156e5c31af7Sopenharmony_ci			/* Zero out the target BO before we begin the TF */
5157e5c31af7Sopenharmony_ci			static const unsigned char data_zero = 0;
5158e5c31af7Sopenharmony_ci
5159e5c31af7Sopenharmony_ci			m_gl.clearBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, GL_R8, GL_RED, GL_UNSIGNED_BYTE, &data_zero);
5160e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glClearBufferData() call failed.");
5161e5c31af7Sopenharmony_ci
5162e5c31af7Sopenharmony_ci			/* Set up transform feed-back buffer bindings */
5163e5c31af7Sopenharmony_ci			DE_ASSERT(m_result_bo_size != 0);
5164e5c31af7Sopenharmony_ci
5165e5c31af7Sopenharmony_ci			if (is_ia_iteration)
5166e5c31af7Sopenharmony_ci			{
5167e5c31af7Sopenharmony_ci				DE_ASSERT(m_result_bo != 0);
5168e5c31af7Sopenharmony_ci
5169e5c31af7Sopenharmony_ci				m_gl.bindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* index */
5170e5c31af7Sopenharmony_ci									 m_result_bo, 0,				  /* offset */
5171e5c31af7Sopenharmony_ci									 m_result_bo_size);
5172e5c31af7Sopenharmony_ci
5173e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBufferRange() call failed.");
5174e5c31af7Sopenharmony_ci			}
5175e5c31af7Sopenharmony_ci			else
5176e5c31af7Sopenharmony_ci			{
5177e5c31af7Sopenharmony_ci				DE_ASSERT(m_result_bo_size % 2 == 0);
5178e5c31af7Sopenharmony_ci
5179e5c31af7Sopenharmony_ci				m_gl.bindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* index */
5180e5c31af7Sopenharmony_ci									 m_result_bo, 0,				  /* offset */
5181e5c31af7Sopenharmony_ci									 m_result_bo_size / 2);
5182e5c31af7Sopenharmony_ci				m_gl.bindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 1, /* index */
5183e5c31af7Sopenharmony_ci									 m_result_bo, m_result_bo_size / 2, m_result_bo_size / 2);
5184e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBufferRange() call(s) failed.");
5185e5c31af7Sopenharmony_ci			}
5186e5c31af7Sopenharmony_ci
5187e5c31af7Sopenharmony_ci			m_gl.beginTransformFeedback(GL_POINTS);
5188e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBeginTransformFeedback() call failed.");
5189e5c31af7Sopenharmony_ci
5190e5c31af7Sopenharmony_ci			/* NOTE: Some discussion about the expected "vertex id" value:
5191e5c31af7Sopenharmony_ci			 *
5192e5c31af7Sopenharmony_ci			 * In GL 4.5 core spec (Feb2/2015 version), we have:
5193e5c31af7Sopenharmony_ci			 *
5194e5c31af7Sopenharmony_ci			 * >>
5195e5c31af7Sopenharmony_ci			 * The index of any element transferred to the GL by DrawElementsOneInstance
5196e5c31af7Sopenharmony_ci			 * is referred to as its vertex ID, and may be read by a vertex shader as
5197e5c31af7Sopenharmony_ci			 * gl_VertexID. The vertex ID of the ith element transferred is the sum of
5198e5c31af7Sopenharmony_ci			 * basevertex and the value stored in the currently bound element array buffer at
5199e5c31af7Sopenharmony_ci			 * offset indices +i.
5200e5c31af7Sopenharmony_ci			 * <<
5201e5c31af7Sopenharmony_ci			 *
5202e5c31af7Sopenharmony_ci			 * So for glDrawElements*() derivatives, we will be expecting gl_VertexID to be set to
5203e5c31af7Sopenharmony_ci			 * (basevertex + index[i] + i)
5204e5c31af7Sopenharmony_ci			 *
5205e5c31af7Sopenharmony_ci			 * DrawArrays does not support the "base vertex" concept at all:
5206e5c31af7Sopenharmony_ci			 *
5207e5c31af7Sopenharmony_ci			 * >>
5208e5c31af7Sopenharmony_ci			 * The index of any element transferred to the GL by DrawArraysOneInstance
5209e5c31af7Sopenharmony_ci			 * is referred to as its vertex ID, and may be read by a vertex shader as gl_VertexID.
5210e5c31af7Sopenharmony_ci			 * The vertex ID of the ith element transferred is first + i.
5211e5c31af7Sopenharmony_ci			 * <<
5212e5c31af7Sopenharmony_ci			 *
5213e5c31af7Sopenharmony_ci			 * For regular draw calls, gl_VertexID should be of form:
5214e5c31af7Sopenharmony_ci			 *
5215e5c31af7Sopenharmony_ci			 * (first + i)
5216e5c31af7Sopenharmony_ci			 *
5217e5c31af7Sopenharmony_ci			 * In both cases, gl_InstanceID does NOT include the baseinstance value, as per:
5218e5c31af7Sopenharmony_ci			 *
5219e5c31af7Sopenharmony_ci			 * >>
5220e5c31af7Sopenharmony_ci			 * If an enabled vertex attribute array is instanced (it has a non-zero divisor as
5221e5c31af7Sopenharmony_ci			 * specified by VertexAttribDivisor), the element index that is transferred to the GL,
5222e5c31af7Sopenharmony_ci			 * for all vertices, is given by
5223e5c31af7Sopenharmony_ci			 *
5224e5c31af7Sopenharmony_ci			 * floor(instance / divisor) + baseinstance
5225e5c31af7Sopenharmony_ci			 *
5226e5c31af7Sopenharmony_ci			 * The value of instance may be read by a vertex shader as gl_InstanceID, as
5227e5c31af7Sopenharmony_ci			 * described in section 11.1.3.9
5228e5c31af7Sopenharmony_ci			 * <<
5229e5c31af7Sopenharmony_ci			 */
5230e5c31af7Sopenharmony_ci			switch (draw_call_type)
5231e5c31af7Sopenharmony_ci			{
5232e5c31af7Sopenharmony_ci			case DRAW_CALL_INDEXED:
5233e5c31af7Sopenharmony_ci			{
5234e5c31af7Sopenharmony_ci				m_gl.drawElements(GL_POINTS, m_n_vertices_per_instance, GL_UNSIGNED_INT,
5235e5c31af7Sopenharmony_ci								  (const glw::GLvoid*)(intptr_t)m_data_bo_index_data_offset);
5236e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawElements() call failed.");
5237e5c31af7Sopenharmony_ci
5238e5c31af7Sopenharmony_ci				draw_call_count					 = 1;
5239e5c31af7Sopenharmony_ci				draw_call_first_instance_id[0]   = 0;
5240e5c31af7Sopenharmony_ci				draw_call_first_vertex_id[0]	 = m_n_vertices_per_instance;
5241e5c31af7Sopenharmony_ci				draw_call_is_vertex_id_ascending = false;
5242e5c31af7Sopenharmony_ci				draw_call_n_instances[0]		 = 1;
5243e5c31af7Sopenharmony_ci				draw_call_n_vertices[0]			 = m_n_vertices_per_instance;
5244e5c31af7Sopenharmony_ci				n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * m_n_vertices_per_instance;
5245e5c31af7Sopenharmony_ci				n_result_bytes_total			 = n_result_bytes_per_instance[0] * draw_call_n_instances[0];
5246e5c31af7Sopenharmony_ci
5247e5c31af7Sopenharmony_ci				break;
5248e5c31af7Sopenharmony_ci			}
5249e5c31af7Sopenharmony_ci
5250e5c31af7Sopenharmony_ci			case DRAW_CALL_INDEXED_BASE_VERTEX:
5251e5c31af7Sopenharmony_ci			{
5252e5c31af7Sopenharmony_ci				m_gl.drawElementsBaseVertex(GL_POINTS, m_n_vertices_per_instance, GL_UNSIGNED_INT,
5253e5c31af7Sopenharmony_ci											(const glw::GLvoid*)(intptr_t)m_data_bo_index_data_offset,
5254e5c31af7Sopenharmony_ci											m_draw_call_baseVertex);
5255e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawElementsBaseVertex() call failed.");
5256e5c31af7Sopenharmony_ci
5257e5c31af7Sopenharmony_ci				draw_call_count					 = 1;
5258e5c31af7Sopenharmony_ci				draw_call_first_instance_id[0]   = 0;
5259e5c31af7Sopenharmony_ci				draw_call_first_vertex_id[0]	 = m_draw_call_baseVertex + m_n_vertices_per_instance;
5260e5c31af7Sopenharmony_ci				draw_call_is_vertex_id_ascending = false;
5261e5c31af7Sopenharmony_ci				draw_call_n_instances[0]		 = 1;
5262e5c31af7Sopenharmony_ci				draw_call_n_vertices[0]			 = m_n_vertices_per_instance;
5263e5c31af7Sopenharmony_ci				n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * m_n_vertices_per_instance;
5264e5c31af7Sopenharmony_ci				n_result_bytes_total			 = n_result_bytes_per_instance[0] * draw_call_n_instances[0];
5265e5c31af7Sopenharmony_ci
5266e5c31af7Sopenharmony_ci				break;
5267e5c31af7Sopenharmony_ci			}
5268e5c31af7Sopenharmony_ci
5269e5c31af7Sopenharmony_ci			case DRAW_CALL_INDEXED_INDIRECT:
5270e5c31af7Sopenharmony_ci			{
5271e5c31af7Sopenharmony_ci				m_gl.drawElementsIndirect(GL_POINTS, GL_UNSIGNED_INT,
5272e5c31af7Sopenharmony_ci										  (const glw::GLvoid*)(intptr_t)m_data_bo_indexed_indirect_arg_offset);
5273e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawElementsIndirect() call failed.");
5274e5c31af7Sopenharmony_ci
5275e5c31af7Sopenharmony_ci				draw_call_count				   = 1;
5276e5c31af7Sopenharmony_ci				draw_call_first_instance_id[0] = 0;
5277e5c31af7Sopenharmony_ci				draw_call_first_vertex_id[0] =
5278e5c31af7Sopenharmony_ci					m_draw_call_baseVertex +
5279e5c31af7Sopenharmony_ci					m_index_data[((unsigned int)(intptr_t)m_multidrawcall_index[1] - m_data_bo_index_data_offset) /
5280e5c31af7Sopenharmony_ci								 sizeof(unsigned int)];
5281e5c31af7Sopenharmony_ci				draw_call_is_vertex_id_ascending = false;
5282e5c31af7Sopenharmony_ci				draw_call_n_instances[0]		 = m_n_instances_to_test;
5283e5c31af7Sopenharmony_ci				draw_call_n_vertices[0]			 = m_multidrawcall_count[1];
5284e5c31af7Sopenharmony_ci				n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * draw_call_n_vertices[0];
5285e5c31af7Sopenharmony_ci				n_result_bytes_total			 = n_result_bytes_per_instance[0] * draw_call_n_instances[0];
5286e5c31af7Sopenharmony_ci
5287e5c31af7Sopenharmony_ci				break;
5288e5c31af7Sopenharmony_ci			}
5289e5c31af7Sopenharmony_ci
5290e5c31af7Sopenharmony_ci			case DRAW_CALL_INDEXED_INDIRECT_MULTI:
5291e5c31af7Sopenharmony_ci			{
5292e5c31af7Sopenharmony_ci				m_gl.multiDrawElementsIndirect(GL_POINTS, GL_UNSIGNED_INT,
5293e5c31af7Sopenharmony_ci											   (const glw::GLvoid*)(intptr_t)m_data_bo_indexed_mdi_arg_offset,
5294e5c31af7Sopenharmony_ci											   m_multidrawcall_drawcount, 0); /* stride */
5295e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMultiDrawElementsIndirect() call failed.");
5296e5c31af7Sopenharmony_ci
5297e5c31af7Sopenharmony_ci				draw_call_count				   = m_multidrawcall_drawcount;
5298e5c31af7Sopenharmony_ci				draw_call_first_instance_id[0] = 0;
5299e5c31af7Sopenharmony_ci				draw_call_first_instance_id[1] = 0;
5300e5c31af7Sopenharmony_ci				draw_call_first_vertex_id[0] =
5301e5c31af7Sopenharmony_ci					m_draw_call_baseVertex +
5302e5c31af7Sopenharmony_ci					m_index_data[((unsigned int)(intptr_t)m_multidrawcall_index[0] - m_data_bo_index_data_offset) /
5303e5c31af7Sopenharmony_ci								 sizeof(unsigned int)];
5304e5c31af7Sopenharmony_ci				draw_call_first_vertex_id[1] =
5305e5c31af7Sopenharmony_ci					m_draw_call_baseVertex +
5306e5c31af7Sopenharmony_ci					m_index_data[((unsigned int)(intptr_t)m_multidrawcall_index[1] - m_data_bo_index_data_offset) /
5307e5c31af7Sopenharmony_ci								 sizeof(unsigned int)];
5308e5c31af7Sopenharmony_ci				draw_call_is_vertex_id_ascending = false;
5309e5c31af7Sopenharmony_ci				draw_call_n_instances[0]		 = 1;
5310e5c31af7Sopenharmony_ci				draw_call_n_instances[1]		 = m_n_instances_to_test;
5311e5c31af7Sopenharmony_ci				draw_call_n_vertices[0]			 = m_multidrawcall_count[0];
5312e5c31af7Sopenharmony_ci				draw_call_n_vertices[1]			 = m_multidrawcall_count[1];
5313e5c31af7Sopenharmony_ci				n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * draw_call_n_vertices[0];
5314e5c31af7Sopenharmony_ci				n_result_bytes_per_instance[1]   = n_result_bytes_per_vertex * draw_call_n_vertices[1];
5315e5c31af7Sopenharmony_ci				n_result_bytes_total			 = n_result_bytes_per_instance[0] * draw_call_n_instances[0] +
5316e5c31af7Sopenharmony_ci									   n_result_bytes_per_instance[1] * draw_call_n_instances[1];
5317e5c31af7Sopenharmony_ci
5318e5c31af7Sopenharmony_ci				break;
5319e5c31af7Sopenharmony_ci			}
5320e5c31af7Sopenharmony_ci
5321e5c31af7Sopenharmony_ci			case DRAW_CALL_INDEXED_MULTI:
5322e5c31af7Sopenharmony_ci			{
5323e5c31af7Sopenharmony_ci				m_gl.multiDrawElements(GL_POINTS, m_multidrawcall_count, GL_UNSIGNED_INT, m_multidrawcall_index,
5324e5c31af7Sopenharmony_ci									   m_multidrawcall_drawcount);
5325e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMultiDrawElements() call failed");
5326e5c31af7Sopenharmony_ci
5327e5c31af7Sopenharmony_ci				draw_call_count				   = m_multidrawcall_drawcount;
5328e5c31af7Sopenharmony_ci				draw_call_first_instance_id[0] = 0;
5329e5c31af7Sopenharmony_ci				draw_call_first_instance_id[1] = 0;
5330e5c31af7Sopenharmony_ci				draw_call_first_vertex_id[0] =
5331e5c31af7Sopenharmony_ci					m_index_data[((unsigned int)(intptr_t)m_multidrawcall_index[0] - m_data_bo_index_data_offset) /
5332e5c31af7Sopenharmony_ci								 sizeof(unsigned int)];
5333e5c31af7Sopenharmony_ci				draw_call_first_vertex_id[1] =
5334e5c31af7Sopenharmony_ci					m_index_data[((unsigned int)(intptr_t)m_multidrawcall_index[1] - m_data_bo_index_data_offset) /
5335e5c31af7Sopenharmony_ci								 sizeof(unsigned int)];
5336e5c31af7Sopenharmony_ci				draw_call_is_vertex_id_ascending = false;
5337e5c31af7Sopenharmony_ci				draw_call_n_instances[0]		 = 1;
5338e5c31af7Sopenharmony_ci				draw_call_n_instances[1]		 = 1;
5339e5c31af7Sopenharmony_ci				draw_call_n_vertices[0]			 = m_multidrawcall_count[0];
5340e5c31af7Sopenharmony_ci				draw_call_n_vertices[1]			 = m_multidrawcall_count[1];
5341e5c31af7Sopenharmony_ci				n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * m_multidrawcall_count[0];
5342e5c31af7Sopenharmony_ci				n_result_bytes_per_instance[1]   = n_result_bytes_per_vertex * m_multidrawcall_count[1];
5343e5c31af7Sopenharmony_ci				n_result_bytes_total			 = n_result_bytes_per_instance[0] * draw_call_n_instances[0] +
5344e5c31af7Sopenharmony_ci									   n_result_bytes_per_instance[1] * draw_call_n_instances[1];
5345e5c31af7Sopenharmony_ci
5346e5c31af7Sopenharmony_ci				break;
5347e5c31af7Sopenharmony_ci			}
5348e5c31af7Sopenharmony_ci
5349e5c31af7Sopenharmony_ci			case DRAW_CALL_INDEXED_MULTI_BASE_VERTEX:
5350e5c31af7Sopenharmony_ci			{
5351e5c31af7Sopenharmony_ci				m_gl.multiDrawElementsBaseVertex(GL_POINTS, m_multidrawcall_count, GL_UNSIGNED_INT,
5352e5c31af7Sopenharmony_ci												 m_multidrawcall_index, m_multidrawcall_drawcount,
5353e5c31af7Sopenharmony_ci												 m_multidrawcall_basevertex);
5354e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMultiDrawElementsBaseVertex() call failed.");
5355e5c31af7Sopenharmony_ci
5356e5c31af7Sopenharmony_ci				draw_call_count				   = m_multidrawcall_drawcount;
5357e5c31af7Sopenharmony_ci				draw_call_first_instance_id[0] = 0;
5358e5c31af7Sopenharmony_ci				draw_call_first_instance_id[1] = 0;
5359e5c31af7Sopenharmony_ci				draw_call_first_vertex_id[0] =
5360e5c31af7Sopenharmony_ci					m_multidrawcall_basevertex[0] +
5361e5c31af7Sopenharmony_ci					m_index_data[((unsigned int)(intptr_t)m_multidrawcall_index[0] - m_data_bo_index_data_offset) /
5362e5c31af7Sopenharmony_ci								 sizeof(unsigned int)];
5363e5c31af7Sopenharmony_ci				draw_call_first_vertex_id[1] =
5364e5c31af7Sopenharmony_ci					m_multidrawcall_basevertex[1] +
5365e5c31af7Sopenharmony_ci					m_index_data[((unsigned int)(intptr_t)m_multidrawcall_index[1] - m_data_bo_index_data_offset) /
5366e5c31af7Sopenharmony_ci								 sizeof(unsigned int)];
5367e5c31af7Sopenharmony_ci				draw_call_is_vertex_id_ascending = false;
5368e5c31af7Sopenharmony_ci				draw_call_n_instances[0]		 = 1;
5369e5c31af7Sopenharmony_ci				draw_call_n_instances[1]		 = 1;
5370e5c31af7Sopenharmony_ci				draw_call_n_vertices[0]			 = m_multidrawcall_count[0];
5371e5c31af7Sopenharmony_ci				draw_call_n_vertices[1]			 = m_multidrawcall_count[1];
5372e5c31af7Sopenharmony_ci				n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * m_multidrawcall_count[0];
5373e5c31af7Sopenharmony_ci				n_result_bytes_per_instance[1]   = n_result_bytes_per_vertex * m_multidrawcall_count[1];
5374e5c31af7Sopenharmony_ci				n_result_bytes_total			 = n_result_bytes_per_instance[0] * draw_call_n_instances[0] +
5375e5c31af7Sopenharmony_ci									   n_result_bytes_per_instance[1] * draw_call_n_instances[1];
5376e5c31af7Sopenharmony_ci
5377e5c31af7Sopenharmony_ci				break;
5378e5c31af7Sopenharmony_ci			}
5379e5c31af7Sopenharmony_ci
5380e5c31af7Sopenharmony_ci			case DRAW_CALL_INSTANCED_INDEXED:
5381e5c31af7Sopenharmony_ci			{
5382e5c31af7Sopenharmony_ci				m_gl.drawElementsInstanced(GL_POINTS, m_n_vertices_per_instance, GL_UNSIGNED_INT,
5383e5c31af7Sopenharmony_ci										   (const glw::GLvoid*)(intptr_t)m_data_bo_index_data_offset,
5384e5c31af7Sopenharmony_ci										   m_n_instances_to_test);
5385e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawElementsInstanced() call failed.");
5386e5c31af7Sopenharmony_ci
5387e5c31af7Sopenharmony_ci				draw_call_count					 = 1;
5388e5c31af7Sopenharmony_ci				draw_call_first_instance_id[0]   = 0;
5389e5c31af7Sopenharmony_ci				draw_call_first_vertex_id[0]	 = m_index_data[0];
5390e5c31af7Sopenharmony_ci				draw_call_is_vertex_id_ascending = false;
5391e5c31af7Sopenharmony_ci				draw_call_n_instances[0]		 = m_n_instances_to_test;
5392e5c31af7Sopenharmony_ci				draw_call_n_vertices[0]			 = m_n_vertices_per_instance;
5393e5c31af7Sopenharmony_ci				n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * m_n_vertices_per_instance;
5394e5c31af7Sopenharmony_ci				n_result_bytes_total			 = n_result_bytes_per_instance[0] * draw_call_n_instances[0];
5395e5c31af7Sopenharmony_ci
5396e5c31af7Sopenharmony_ci				break;
5397e5c31af7Sopenharmony_ci			}
5398e5c31af7Sopenharmony_ci
5399e5c31af7Sopenharmony_ci			case DRAW_CALL_INSTANCED_INDEXED_BASE_VERTEX:
5400e5c31af7Sopenharmony_ci			{
5401e5c31af7Sopenharmony_ci				m_gl.drawElementsInstancedBaseVertex(GL_POINTS, m_n_vertices_per_instance, GL_UNSIGNED_INT,
5402e5c31af7Sopenharmony_ci													 (const glw::GLvoid*)(intptr_t)m_data_bo_index_data_offset,
5403e5c31af7Sopenharmony_ci													 m_n_instances_to_test, m_draw_call_baseVertex);
5404e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawElementsInstancedBaseVertex() call failed.");
5405e5c31af7Sopenharmony_ci
5406e5c31af7Sopenharmony_ci				draw_call_count					 = 1;
5407e5c31af7Sopenharmony_ci				draw_call_first_instance_id[0]   = 0;
5408e5c31af7Sopenharmony_ci				draw_call_first_vertex_id[0]	 = m_draw_call_baseVertex + m_index_data[0];
5409e5c31af7Sopenharmony_ci				draw_call_is_vertex_id_ascending = false;
5410e5c31af7Sopenharmony_ci				draw_call_n_instances[0]		 = m_n_instances_to_test;
5411e5c31af7Sopenharmony_ci				draw_call_n_vertices[0]			 = m_n_vertices_per_instance;
5412e5c31af7Sopenharmony_ci				n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * m_n_vertices_per_instance;
5413e5c31af7Sopenharmony_ci				n_result_bytes_total			 = n_result_bytes_per_instance[0] * draw_call_n_instances[0];
5414e5c31af7Sopenharmony_ci
5415e5c31af7Sopenharmony_ci				break;
5416e5c31af7Sopenharmony_ci			}
5417e5c31af7Sopenharmony_ci
5418e5c31af7Sopenharmony_ci			case DRAW_CALL_INSTANCED_INDEXED_BASE_VERTEX_BASE_INSTANCE:
5419e5c31af7Sopenharmony_ci			{
5420e5c31af7Sopenharmony_ci				m_gl.drawElementsInstancedBaseVertexBaseInstance(
5421e5c31af7Sopenharmony_ci					GL_POINTS, m_n_vertices_per_instance, GL_UNSIGNED_INT,
5422e5c31af7Sopenharmony_ci					(const glw::GLvoid*)(intptr_t)m_data_bo_index_data_offset, m_n_instances_to_test,
5423e5c31af7Sopenharmony_ci					m_draw_call_baseVertex, m_draw_call_baseInstance);
5424e5c31af7Sopenharmony_ci
5425e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawElementsInstancedBaseVertexBaseInstance() call failed.");
5426e5c31af7Sopenharmony_ci
5427e5c31af7Sopenharmony_ci				draw_call_count					 = 1;
5428e5c31af7Sopenharmony_ci				draw_call_first_instance_id[0]   = 0;
5429e5c31af7Sopenharmony_ci				draw_call_first_vertex_id[0]	 = m_draw_call_baseVertex + m_index_data[0];
5430e5c31af7Sopenharmony_ci				draw_call_is_vertex_id_ascending = false;
5431e5c31af7Sopenharmony_ci				draw_call_n_instances[0]		 = m_n_instances_to_test;
5432e5c31af7Sopenharmony_ci				draw_call_n_vertices[0]			 = m_n_vertices_per_instance;
5433e5c31af7Sopenharmony_ci				n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * m_n_vertices_per_instance;
5434e5c31af7Sopenharmony_ci				n_result_bytes_total			 = n_result_bytes_per_instance[0] * draw_call_n_instances[0];
5435e5c31af7Sopenharmony_ci
5436e5c31af7Sopenharmony_ci				break;
5437e5c31af7Sopenharmony_ci			}
5438e5c31af7Sopenharmony_ci
5439e5c31af7Sopenharmony_ci			case DRAW_CALL_REGULAR:
5440e5c31af7Sopenharmony_ci			{
5441e5c31af7Sopenharmony_ci				m_gl.drawArrays(GL_POINTS, m_draw_call_first, m_n_vertices_per_instance);
5442e5c31af7Sopenharmony_ci
5443e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArrays() call failed");
5444e5c31af7Sopenharmony_ci
5445e5c31af7Sopenharmony_ci				draw_call_count					 = 1;
5446e5c31af7Sopenharmony_ci				draw_call_first_instance_id[0]   = 0;
5447e5c31af7Sopenharmony_ci				draw_call_first_vertex_id[0]	 = m_draw_call_first;
5448e5c31af7Sopenharmony_ci				draw_call_is_vertex_id_ascending = true;
5449e5c31af7Sopenharmony_ci				draw_call_n_instances[0]		 = 1;
5450e5c31af7Sopenharmony_ci				draw_call_n_vertices[0]			 = m_n_vertices_per_instance;
5451e5c31af7Sopenharmony_ci				n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * m_n_vertices_per_instance;
5452e5c31af7Sopenharmony_ci				n_result_bytes_total			 = n_result_bytes_per_instance[0] * draw_call_n_instances[0];
5453e5c31af7Sopenharmony_ci
5454e5c31af7Sopenharmony_ci				break;
5455e5c31af7Sopenharmony_ci			}
5456e5c31af7Sopenharmony_ci
5457e5c31af7Sopenharmony_ci			case DRAW_CALL_REGULAR_INDIRECT:
5458e5c31af7Sopenharmony_ci			{
5459e5c31af7Sopenharmony_ci				m_gl.drawArraysIndirect(GL_POINTS, (glw::GLvoid*)(intptr_t)m_data_bo_regular_indirect_arg_offset);
5460e5c31af7Sopenharmony_ci
5461e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArraysIndirect() call failed.");
5462e5c31af7Sopenharmony_ci
5463e5c31af7Sopenharmony_ci				draw_call_count					 = 1;
5464e5c31af7Sopenharmony_ci				draw_call_first_instance_id[0]   = 0;
5465e5c31af7Sopenharmony_ci				draw_call_first_vertex_id[0]	 = m_draw_call_first;
5466e5c31af7Sopenharmony_ci				draw_call_is_vertex_id_ascending = true;
5467e5c31af7Sopenharmony_ci				draw_call_n_instances[0]		 = m_n_instances_to_test;
5468e5c31af7Sopenharmony_ci				draw_call_n_vertices[0]			 = m_multidrawcall_count[1];
5469e5c31af7Sopenharmony_ci				n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * draw_call_n_vertices[0];
5470e5c31af7Sopenharmony_ci				n_result_bytes_total			 = n_result_bytes_per_instance[0] * draw_call_n_instances[0];
5471e5c31af7Sopenharmony_ci
5472e5c31af7Sopenharmony_ci				break;
5473e5c31af7Sopenharmony_ci			}
5474e5c31af7Sopenharmony_ci
5475e5c31af7Sopenharmony_ci			case DRAW_CALL_REGULAR_INDIRECT_MULTI:
5476e5c31af7Sopenharmony_ci			{
5477e5c31af7Sopenharmony_ci				m_gl.multiDrawArraysIndirect(GL_POINTS, (glw::GLvoid*)(intptr_t)m_data_bo_regular_mdi_arg_offset,
5478e5c31af7Sopenharmony_ci											 m_multidrawcall_drawcount, 0); /* stride */
5479e5c31af7Sopenharmony_ci
5480e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMultiDrawArraysIndirect() call failed.");
5481e5c31af7Sopenharmony_ci
5482e5c31af7Sopenharmony_ci				draw_call_count					 = 2;
5483e5c31af7Sopenharmony_ci				draw_call_first_instance_id[0]   = 0;
5484e5c31af7Sopenharmony_ci				draw_call_first_instance_id[1]   = 0;
5485e5c31af7Sopenharmony_ci				draw_call_first_vertex_id[0]	 = m_draw_call_first;
5486e5c31af7Sopenharmony_ci				draw_call_first_vertex_id[1]	 = m_draw_call_first;
5487e5c31af7Sopenharmony_ci				draw_call_is_vertex_id_ascending = true;
5488e5c31af7Sopenharmony_ci				draw_call_n_instances[0]		 = 1;
5489e5c31af7Sopenharmony_ci				draw_call_n_instances[1]		 = m_n_instances_to_test;
5490e5c31af7Sopenharmony_ci				draw_call_n_vertices[0]			 = m_multidrawcall_count[0];
5491e5c31af7Sopenharmony_ci				draw_call_n_vertices[1]			 = m_multidrawcall_count[1];
5492e5c31af7Sopenharmony_ci				n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * draw_call_n_vertices[0];
5493e5c31af7Sopenharmony_ci				n_result_bytes_per_instance[1]   = n_result_bytes_per_vertex * draw_call_n_vertices[1];
5494e5c31af7Sopenharmony_ci				n_result_bytes_total			 = n_result_bytes_per_instance[0] * draw_call_n_instances[0] +
5495e5c31af7Sopenharmony_ci									   n_result_bytes_per_instance[1] * draw_call_n_instances[1];
5496e5c31af7Sopenharmony_ci
5497e5c31af7Sopenharmony_ci				break;
5498e5c31af7Sopenharmony_ci			}
5499e5c31af7Sopenharmony_ci
5500e5c31af7Sopenharmony_ci			case DRAW_CALL_REGULAR_INSTANCED:
5501e5c31af7Sopenharmony_ci			{
5502e5c31af7Sopenharmony_ci				m_gl.drawArraysInstanced(GL_POINTS, m_draw_call_first, m_n_vertices_per_instance,
5503e5c31af7Sopenharmony_ci										 m_n_instances_to_test);
5504e5c31af7Sopenharmony_ci
5505e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArraysInstanced() call failed.");
5506e5c31af7Sopenharmony_ci
5507e5c31af7Sopenharmony_ci				draw_call_count					 = 1;
5508e5c31af7Sopenharmony_ci				draw_call_first_instance_id[0]   = 0;
5509e5c31af7Sopenharmony_ci				draw_call_first_vertex_id[0]	 = m_draw_call_first;
5510e5c31af7Sopenharmony_ci				draw_call_is_vertex_id_ascending = true;
5511e5c31af7Sopenharmony_ci				draw_call_n_instances[0]		 = m_n_instances_to_test;
5512e5c31af7Sopenharmony_ci				draw_call_n_vertices[0]			 = m_n_vertices_per_instance;
5513e5c31af7Sopenharmony_ci				n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * draw_call_n_vertices[0];
5514e5c31af7Sopenharmony_ci				n_result_bytes_total			 = n_result_bytes_per_instance[0] * draw_call_n_instances[0];
5515e5c31af7Sopenharmony_ci
5516e5c31af7Sopenharmony_ci				break;
5517e5c31af7Sopenharmony_ci			}
5518e5c31af7Sopenharmony_ci
5519e5c31af7Sopenharmony_ci			case DRAW_CALL_REGULAR_INSTANCED_BASE_INSTANCE:
5520e5c31af7Sopenharmony_ci			{
5521e5c31af7Sopenharmony_ci				m_gl.drawArraysInstancedBaseInstance(GL_POINTS, m_draw_call_first, m_n_vertices_per_instance,
5522e5c31af7Sopenharmony_ci													 m_n_instances_to_test, m_draw_call_baseInstance);
5523e5c31af7Sopenharmony_ci
5524e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArraysInstancedBaseInstance() call failed.");
5525e5c31af7Sopenharmony_ci
5526e5c31af7Sopenharmony_ci				draw_call_count					 = 1;
5527e5c31af7Sopenharmony_ci				draw_call_first_instance_id[0]   = 0;
5528e5c31af7Sopenharmony_ci				draw_call_first_vertex_id[0]	 = m_draw_call_first;
5529e5c31af7Sopenharmony_ci				draw_call_is_vertex_id_ascending = true;
5530e5c31af7Sopenharmony_ci				draw_call_n_instances[0]		 = m_n_instances_to_test;
5531e5c31af7Sopenharmony_ci				draw_call_n_vertices[0]			 = m_n_vertices_per_instance;
5532e5c31af7Sopenharmony_ci				n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * draw_call_n_vertices[0];
5533e5c31af7Sopenharmony_ci				n_result_bytes_total			 = n_result_bytes_per_instance[0] * draw_call_n_instances[0];
5534e5c31af7Sopenharmony_ci
5535e5c31af7Sopenharmony_ci				break;
5536e5c31af7Sopenharmony_ci			}
5537e5c31af7Sopenharmony_ci
5538e5c31af7Sopenharmony_ci			case DRAW_CALL_REGULAR_MULTI:
5539e5c31af7Sopenharmony_ci			{
5540e5c31af7Sopenharmony_ci				m_gl.multiDrawArrays(GL_POINTS, m_multidrawcall_first, m_multidrawcall_count,
5541e5c31af7Sopenharmony_ci									 m_multidrawcall_drawcount);
5542e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMultiDrawArrays() call failed.");
5543e5c31af7Sopenharmony_ci
5544e5c31af7Sopenharmony_ci				draw_call_count					 = m_multidrawcall_drawcount;
5545e5c31af7Sopenharmony_ci				draw_call_first_instance_id[0]   = 0;
5546e5c31af7Sopenharmony_ci				draw_call_first_instance_id[1]   = 0;
5547e5c31af7Sopenharmony_ci				draw_call_first_vertex_id[0]	 = m_multidrawcall_first[0];
5548e5c31af7Sopenharmony_ci				draw_call_first_vertex_id[1]	 = m_multidrawcall_first[1];
5549e5c31af7Sopenharmony_ci				draw_call_is_vertex_id_ascending = true;
5550e5c31af7Sopenharmony_ci				draw_call_n_instances[0]		 = 1;
5551e5c31af7Sopenharmony_ci				draw_call_n_instances[1]		 = 1;
5552e5c31af7Sopenharmony_ci				draw_call_n_vertices[0]			 = m_multidrawcall_count[0];
5553e5c31af7Sopenharmony_ci				draw_call_n_vertices[1]			 = m_multidrawcall_count[1];
5554e5c31af7Sopenharmony_ci				n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * m_multidrawcall_count[0];
5555e5c31af7Sopenharmony_ci				n_result_bytes_per_instance[1]   = n_result_bytes_per_vertex * m_multidrawcall_count[1];
5556e5c31af7Sopenharmony_ci				n_result_bytes_total			 = n_result_bytes_per_instance[0] + n_result_bytes_per_instance[1];
5557e5c31af7Sopenharmony_ci
5558e5c31af7Sopenharmony_ci				break;
5559e5c31af7Sopenharmony_ci			}
5560e5c31af7Sopenharmony_ci
5561e5c31af7Sopenharmony_ci			default:
5562e5c31af7Sopenharmony_ci			{
5563e5c31af7Sopenharmony_ci				TCU_FAIL("Unrecognized draw call type");
5564e5c31af7Sopenharmony_ci			}
5565e5c31af7Sopenharmony_ci			} /* switch (draw_call_type) */
5566e5c31af7Sopenharmony_ci
5567e5c31af7Sopenharmony_ci			DE_ASSERT(n_result_bytes_total <= m_result_bo_size);
5568e5c31af7Sopenharmony_ci
5569e5c31af7Sopenharmony_ci			m_gl.endTransformFeedback();
5570e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glEndTransformFeedback() call failed.");
5571e5c31af7Sopenharmony_ci
5572e5c31af7Sopenharmony_ci			/* Retrieve the captured data */
5573e5c31af7Sopenharmony_ci			glw::GLuint  mappable_bo_id			  = m_helper_bo;
5574e5c31af7Sopenharmony_ci			unsigned int mappable_bo_start_offset = 0;
5575e5c31af7Sopenharmony_ci
5576e5c31af7Sopenharmony_ci			/* We cannot map the result BO storage directly into process space, since
5577e5c31af7Sopenharmony_ci			 * it's a sparse buffer. Copy the generated data to a helper BO and map
5578e5c31af7Sopenharmony_ci			 * that BO instead. */
5579e5c31af7Sopenharmony_ci			m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_result_bo);
5580e5c31af7Sopenharmony_ci			m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_helper_bo);
5581e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call(s) failed.");
5582e5c31af7Sopenharmony_ci
5583e5c31af7Sopenharmony_ci			if (is_ia_iteration)
5584e5c31af7Sopenharmony_ci			{
5585e5c31af7Sopenharmony_ci				m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, /* readOffset */
5586e5c31af7Sopenharmony_ci									   0,											 /* writeOffset */
5587e5c31af7Sopenharmony_ci									   n_result_bytes_total);
5588e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
5589e5c31af7Sopenharmony_ci			}
5590e5c31af7Sopenharmony_ci			else
5591e5c31af7Sopenharmony_ci			{
5592e5c31af7Sopenharmony_ci				DE_ASSERT((n_result_bytes_total % 2) == 0);
5593e5c31af7Sopenharmony_ci
5594e5c31af7Sopenharmony_ci				m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, /* readOffset */
5595e5c31af7Sopenharmony_ci									   0,											 /* writeOffset */
5596e5c31af7Sopenharmony_ci									   n_result_bytes_total / 2);
5597e5c31af7Sopenharmony_ci				m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER,
5598e5c31af7Sopenharmony_ci									   m_result_bo_size / 2,	  /* readOffset  */
5599e5c31af7Sopenharmony_ci									   m_result_bo_size / 2,	  /* writeOffset */
5600e5c31af7Sopenharmony_ci									   n_result_bytes_total / 2); /* size        */
5601e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
5602e5c31af7Sopenharmony_ci			}
5603e5c31af7Sopenharmony_ci
5604e5c31af7Sopenharmony_ci			m_gl.bindBuffer(GL_ARRAY_BUFFER, mappable_bo_id);
5605e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
5606e5c31af7Sopenharmony_ci
5607e5c31af7Sopenharmony_ci			result_ptr = (unsigned int*)m_gl.mapBufferRange(GL_ARRAY_BUFFER, mappable_bo_start_offset, m_result_bo_size,
5608e5c31af7Sopenharmony_ci															GL_MAP_READ_BIT);
5609e5c31af7Sopenharmony_ci
5610e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMapBufferRange() call failed.");
5611e5c31af7Sopenharmony_ci
5612e5c31af7Sopenharmony_ci			/* Verify the generated output */
5613e5c31af7Sopenharmony_ci			bool		continue_checking		  = true;
5614e5c31af7Sopenharmony_ci			glw::GLuint result_instance_id_stride = 0;
5615e5c31af7Sopenharmony_ci			glw::GLuint result_vertex_id_stride   = 0;
5616e5c31af7Sopenharmony_ci
5617e5c31af7Sopenharmony_ci			if (is_ia_iteration)
5618e5c31af7Sopenharmony_ci			{
5619e5c31af7Sopenharmony_ci				result_instance_id_stride = 2;
5620e5c31af7Sopenharmony_ci				result_vertex_id_stride   = 2;
5621e5c31af7Sopenharmony_ci			}
5622e5c31af7Sopenharmony_ci			else
5623e5c31af7Sopenharmony_ci			{
5624e5c31af7Sopenharmony_ci				result_instance_id_stride = 1;
5625e5c31af7Sopenharmony_ci				result_vertex_id_stride   = 1;
5626e5c31af7Sopenharmony_ci			}
5627e5c31af7Sopenharmony_ci
5628e5c31af7Sopenharmony_ci			/* For all draw calls.. */
5629e5c31af7Sopenharmony_ci			for (int n_draw_call = 0; n_draw_call < draw_call_count && continue_checking; ++n_draw_call)
5630e5c31af7Sopenharmony_ci			{
5631e5c31af7Sopenharmony_ci				/* ..and resulting draw call instances.. */
5632e5c31af7Sopenharmony_ci				for (int n_instance = 0; n_instance < draw_call_n_instances[n_draw_call] && continue_checking;
5633e5c31af7Sopenharmony_ci					 ++n_instance)
5634e5c31af7Sopenharmony_ci				{
5635e5c31af7Sopenharmony_ci					DE_ASSERT((n_result_bytes_per_instance[n_draw_call] % sizeof(unsigned int)) == 0);
5636e5c31af7Sopenharmony_ci
5637e5c31af7Sopenharmony_ci					/* Determine where the result TF data start from */
5638e5c31af7Sopenharmony_ci					const glw::GLuint expected_instance_id = draw_call_first_instance_id[n_draw_call] + n_instance;
5639e5c31af7Sopenharmony_ci					glw::GLuint*	  result_instance_id_traveller_ptr = DE_NULL;
5640e5c31af7Sopenharmony_ci					glw::GLuint*	  result_vertex_id_traveller_ptr   = DE_NULL;
5641e5c31af7Sopenharmony_ci
5642e5c31af7Sopenharmony_ci					if (is_ia_iteration)
5643e5c31af7Sopenharmony_ci					{
5644e5c31af7Sopenharmony_ci						result_instance_id_traveller_ptr = result_ptr;
5645e5c31af7Sopenharmony_ci
5646e5c31af7Sopenharmony_ci						for (int n_prev_draw_call = 0; n_prev_draw_call < n_draw_call; ++n_prev_draw_call)
5647e5c31af7Sopenharmony_ci						{
5648e5c31af7Sopenharmony_ci							result_instance_id_traveller_ptr += draw_call_n_instances[n_prev_draw_call] *
5649e5c31af7Sopenharmony_ci																n_result_bytes_per_instance[n_prev_draw_call] /
5650e5c31af7Sopenharmony_ci																sizeof(unsigned int);
5651e5c31af7Sopenharmony_ci						}
5652e5c31af7Sopenharmony_ci
5653e5c31af7Sopenharmony_ci						result_instance_id_traveller_ptr +=
5654e5c31af7Sopenharmony_ci							n_instance * n_result_bytes_per_instance[n_draw_call] / sizeof(unsigned int);
5655e5c31af7Sopenharmony_ci						result_vertex_id_traveller_ptr = result_instance_id_traveller_ptr + 1;
5656e5c31af7Sopenharmony_ci					} /* if (is_ia_iteration) */
5657e5c31af7Sopenharmony_ci					else
5658e5c31af7Sopenharmony_ci					{
5659e5c31af7Sopenharmony_ci						DE_ASSERT((m_result_bo_size % 2) == 0);
5660e5c31af7Sopenharmony_ci
5661e5c31af7Sopenharmony_ci						result_instance_id_traveller_ptr = result_ptr;
5662e5c31af7Sopenharmony_ci
5663e5c31af7Sopenharmony_ci						for (int n_prev_draw_call = 0; n_prev_draw_call < n_draw_call; ++n_prev_draw_call)
5664e5c31af7Sopenharmony_ci						{
5665e5c31af7Sopenharmony_ci							result_instance_id_traveller_ptr +=
5666e5c31af7Sopenharmony_ci								draw_call_n_instances[n_prev_draw_call] *
5667e5c31af7Sopenharmony_ci								n_result_bytes_per_instance[n_prev_draw_call] /
5668e5c31af7Sopenharmony_ci								2 / /* instance id..instance id data | vertex id..vertex id data */
5669e5c31af7Sopenharmony_ci								sizeof(unsigned int);
5670e5c31af7Sopenharmony_ci						}
5671e5c31af7Sopenharmony_ci
5672e5c31af7Sopenharmony_ci						result_instance_id_traveller_ptr +=
5673e5c31af7Sopenharmony_ci							n_instance * n_result_bytes_per_instance[n_draw_call] / 2 / sizeof(unsigned int);
5674e5c31af7Sopenharmony_ci						result_vertex_id_traveller_ptr =
5675e5c31af7Sopenharmony_ci							result_instance_id_traveller_ptr + (m_result_bo_size / 2) / sizeof(unsigned int);
5676e5c31af7Sopenharmony_ci					}
5677e5c31af7Sopenharmony_ci
5678e5c31af7Sopenharmony_ci					/* Start checking the generated output */
5679e5c31af7Sopenharmony_ci					for (int n_point = 0; n_point < draw_call_n_vertices[n_draw_call] && continue_checking; ++n_point)
5680e5c31af7Sopenharmony_ci					{
5681e5c31af7Sopenharmony_ci						glw::GLuint expected_vertex_id	= 1;
5682e5c31af7Sopenharmony_ci						glw::GLuint retrieved_instance_id = 2;
5683e5c31af7Sopenharmony_ci						glw::GLuint retrieved_vertex_id   = 3;
5684e5c31af7Sopenharmony_ci
5685e5c31af7Sopenharmony_ci						if (draw_call_is_vertex_id_ascending)
5686e5c31af7Sopenharmony_ci						{
5687e5c31af7Sopenharmony_ci							expected_vertex_id = draw_call_first_vertex_id[n_draw_call] + n_point;
5688e5c31af7Sopenharmony_ci						} /* if (draw_call_is_vertex_id_ascending) */
5689e5c31af7Sopenharmony_ci						else
5690e5c31af7Sopenharmony_ci						{
5691e5c31af7Sopenharmony_ci							if (draw_call_first_vertex_id[n_draw_call] >= n_point)
5692e5c31af7Sopenharmony_ci							{
5693e5c31af7Sopenharmony_ci								expected_vertex_id = draw_call_first_vertex_id[n_draw_call] - n_point;
5694e5c31af7Sopenharmony_ci							}
5695e5c31af7Sopenharmony_ci							else
5696e5c31af7Sopenharmony_ci							{
5697e5c31af7Sopenharmony_ci								expected_vertex_id = 0;
5698e5c31af7Sopenharmony_ci							}
5699e5c31af7Sopenharmony_ci						}
5700e5c31af7Sopenharmony_ci
5701e5c31af7Sopenharmony_ci						/* Only perform the check if the offsets refer to pages with physical backing.
5702e5c31af7Sopenharmony_ci						 *
5703e5c31af7Sopenharmony_ci						 * Note that, on platforms, whose page size % 4 != 0, the values can land partially out of bounds,
5704e5c31af7Sopenharmony_ci						 * and partially in the safe zone. In such cases, skip the verification. */
5705e5c31af7Sopenharmony_ci						const bool result_instance_id_page_has_physical_backing =
5706e5c31af7Sopenharmony_ci							(((((char*)result_instance_id_traveller_ptr - (char*)result_ptr) / m_page_size) % 2) ==
5707e5c31af7Sopenharmony_ci							 0) &&
5708e5c31af7Sopenharmony_ci							((((((char*)result_instance_id_traveller_ptr - (char*)result_ptr) + sizeof(unsigned int) -
5709e5c31af7Sopenharmony_ci								1) /
5710e5c31af7Sopenharmony_ci							   m_page_size) %
5711e5c31af7Sopenharmony_ci							  2) == 0);
5712e5c31af7Sopenharmony_ci						const bool result_vertex_id_page_has_physical_backing =
5713e5c31af7Sopenharmony_ci							(((((char*)result_vertex_id_traveller_ptr - (char*)result_ptr) / m_page_size) % 2) == 0) &&
5714e5c31af7Sopenharmony_ci							((((((char*)result_vertex_id_traveller_ptr - (char*)result_ptr) + sizeof(unsigned int) -
5715e5c31af7Sopenharmony_ci								1) /
5716e5c31af7Sopenharmony_ci							   m_page_size) %
5717e5c31af7Sopenharmony_ci							  2) == 0);
5718e5c31af7Sopenharmony_ci
5719e5c31af7Sopenharmony_ci						retrieved_instance_id = *result_instance_id_traveller_ptr;
5720e5c31af7Sopenharmony_ci						result_instance_id_traveller_ptr += result_instance_id_stride;
5721e5c31af7Sopenharmony_ci
5722e5c31af7Sopenharmony_ci						retrieved_vertex_id = *result_vertex_id_traveller_ptr;
5723e5c31af7Sopenharmony_ci						result_vertex_id_traveller_ptr += result_vertex_id_stride;
5724e5c31af7Sopenharmony_ci
5725e5c31af7Sopenharmony_ci						if ((result_instance_id_page_has_physical_backing &&
5726e5c31af7Sopenharmony_ci							 retrieved_instance_id != expected_instance_id) ||
5727e5c31af7Sopenharmony_ci							(result_vertex_id_page_has_physical_backing && retrieved_vertex_id != expected_vertex_id))
5728e5c31af7Sopenharmony_ci						{
5729e5c31af7Sopenharmony_ci							m_testCtx.getLog()
5730e5c31af7Sopenharmony_ci								<< tcu::TestLog::Message << "For "
5731e5c31af7Sopenharmony_ci															"["
5732e5c31af7Sopenharmony_ci								<< getName() << "]"
5733e5c31af7Sopenharmony_ci												", sparse BO flags "
5734e5c31af7Sopenharmony_ci												"["
5735e5c31af7Sopenharmony_ci								<< SparseBufferTestUtilities::getSparseBOFlagsString(sparse_bo_storage_flags)
5736e5c31af7Sopenharmony_ci								<< "]"
5737e5c31af7Sopenharmony_ci								   ", draw call type "
5738e5c31af7Sopenharmony_ci								<< getDrawCallTypeString(draw_call_type) << " at index "
5739e5c31af7Sopenharmony_ci																			"["
5740e5c31af7Sopenharmony_ci								<< n_draw_call << " / " << (draw_call_count - 1) << "]"
5741e5c31af7Sopenharmony_ci																					", TF mode "
5742e5c31af7Sopenharmony_ci																					"["
5743e5c31af7Sopenharmony_ci								<< ((is_ia_iteration) ? "interleaved attribs" : "separate attribs") << "]"
5744e5c31af7Sopenharmony_ci								<< ", instance "
5745e5c31af7Sopenharmony_ci								   "["
5746e5c31af7Sopenharmony_ci								<< n_instance << " / " << (draw_call_n_instances[n_draw_call] - 1) << "]"
5747e5c31af7Sopenharmony_ci								<< ", point at index "
5748e5c31af7Sopenharmony_ci								   "["
5749e5c31af7Sopenharmony_ci								<< n_point << " / " << (draw_call_n_vertices[n_draw_call] - 1) << "]"
5750e5c31af7Sopenharmony_ci								<< ", VS-level gl_VertexID was equal to "
5751e5c31af7Sopenharmony_ci								   "["
5752e5c31af7Sopenharmony_ci								<< retrieved_vertex_id << "]"
5753e5c31af7Sopenharmony_ci														  " and gl_InstanceID was set to "
5754e5c31af7Sopenharmony_ci														  "["
5755e5c31af7Sopenharmony_ci								<< retrieved_instance_id << "]"
5756e5c31af7Sopenharmony_ci															", whereas gl_VertexID of value "
5757e5c31af7Sopenharmony_ci															"["
5758e5c31af7Sopenharmony_ci								<< expected_vertex_id << "]"
5759e5c31af7Sopenharmony_ci														 " and gl_InstanceID of value "
5760e5c31af7Sopenharmony_ci														 "["
5761e5c31af7Sopenharmony_ci								<< expected_instance_id << "]"
5762e5c31af7Sopenharmony_ci														   " were anticipated."
5763e5c31af7Sopenharmony_ci								<< tcu::TestLog::EndMessage;
5764e5c31af7Sopenharmony_ci
5765e5c31af7Sopenharmony_ci							continue_checking = false;
5766e5c31af7Sopenharmony_ci							result			  = false;
5767e5c31af7Sopenharmony_ci
5768e5c31af7Sopenharmony_ci							break;
5769e5c31af7Sopenharmony_ci						} /* if (reported gl_InstanceID / gl_VertexID values are wrong) */
5770e5c31af7Sopenharmony_ci					}	 /* for (all drawn points) */
5771e5c31af7Sopenharmony_ci				}		  /* for (all instances) */
5772e5c31af7Sopenharmony_ci
5773e5c31af7Sopenharmony_ci				/* Release memory pages we have allocated for the transform feed-back.
5774e5c31af7Sopenharmony_ci				 *
5775e5c31af7Sopenharmony_ci				 * NOTE: For some iterations, this call will attempt to de-commit pages which
5776e5c31af7Sopenharmony_ci				 *       have not been assigned physical backing. This is a valid behavior,
5777e5c31af7Sopenharmony_ci				 *       as per spec.
5778e5c31af7Sopenharmony_ci				 */
5779e5c31af7Sopenharmony_ci				m_gl.bufferPageCommitmentARB(GL_TRANSFORM_FEEDBACK_BUFFER, 0,	 /* offset */
5780e5c31af7Sopenharmony_ci											 m_result_bo_size_rounded, GL_FALSE); /* commit */
5781e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
5782e5c31af7Sopenharmony_ci			} /* for (all draw call) */
5783e5c31af7Sopenharmony_ci
5784e5c31af7Sopenharmony_ci			m_gl.unmapBuffer(GL_ARRAY_BUFFER);
5785e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUnmapBuffer() call failed.");
5786e5c31af7Sopenharmony_ci		} /* for (all draw call types) */
5787e5c31af7Sopenharmony_ci	}	 /* for (both TF modes) */
5788e5c31af7Sopenharmony_ci
5789e5c31af7Sopenharmony_ci	return result;
5790e5c31af7Sopenharmony_ci}
5791e5c31af7Sopenharmony_ci
5792e5c31af7Sopenharmony_ci/** Converts the internal enum to a null-terminated text string.
5793e5c31af7Sopenharmony_ci *
5794e5c31af7Sopenharmony_ci *  @param draw_call Draw call type to return a string for.
5795e5c31af7Sopenharmony_ci *
5796e5c31af7Sopenharmony_ci *  @return The requested string or "[?!]", if the enum was not recognized.
5797e5c31af7Sopenharmony_ci **/
5798e5c31af7Sopenharmony_ciconst char* TransformFeedbackBufferStorageTestCase::getDrawCallTypeString(_draw_call draw_call)
5799e5c31af7Sopenharmony_ci{
5800e5c31af7Sopenharmony_ci	const char* result = "[?!]";
5801e5c31af7Sopenharmony_ci
5802e5c31af7Sopenharmony_ci	switch (draw_call)
5803e5c31af7Sopenharmony_ci	{
5804e5c31af7Sopenharmony_ci	case DRAW_CALL_INDEXED:
5805e5c31af7Sopenharmony_ci		result = "glDrawElements()";
5806e5c31af7Sopenharmony_ci		break;
5807e5c31af7Sopenharmony_ci	case DRAW_CALL_INDEXED_BASE_VERTEX:
5808e5c31af7Sopenharmony_ci		result = "glDrawElementsBaseVertex()";
5809e5c31af7Sopenharmony_ci		break;
5810e5c31af7Sopenharmony_ci	case DRAW_CALL_INDEXED_INDIRECT:
5811e5c31af7Sopenharmony_ci		result = "glDrawElementsIndirect()";
5812e5c31af7Sopenharmony_ci		break;
5813e5c31af7Sopenharmony_ci	case DRAW_CALL_INDEXED_INDIRECT_MULTI:
5814e5c31af7Sopenharmony_ci		result = "glMultiDrawElementIndirect()";
5815e5c31af7Sopenharmony_ci		break;
5816e5c31af7Sopenharmony_ci	case DRAW_CALL_INDEXED_MULTI:
5817e5c31af7Sopenharmony_ci		result = "glMultiDrawElements()";
5818e5c31af7Sopenharmony_ci		break;
5819e5c31af7Sopenharmony_ci	case DRAW_CALL_INDEXED_MULTI_BASE_VERTEX:
5820e5c31af7Sopenharmony_ci		result = "glMultiDrawElementsBaseVertex()";
5821e5c31af7Sopenharmony_ci		break;
5822e5c31af7Sopenharmony_ci	case DRAW_CALL_INSTANCED_INDEXED:
5823e5c31af7Sopenharmony_ci		result = "glDrawElementsInstanced()";
5824e5c31af7Sopenharmony_ci		break;
5825e5c31af7Sopenharmony_ci	case DRAW_CALL_INSTANCED_INDEXED_BASE_VERTEX:
5826e5c31af7Sopenharmony_ci		result = "glDrawElementsInstancedBaseVertex()";
5827e5c31af7Sopenharmony_ci		break;
5828e5c31af7Sopenharmony_ci	case DRAW_CALL_INSTANCED_INDEXED_BASE_VERTEX_BASE_INSTANCE:
5829e5c31af7Sopenharmony_ci		result = "glDrawElementsInstancedBaseVertexBaseInstance()";
5830e5c31af7Sopenharmony_ci		break;
5831e5c31af7Sopenharmony_ci	case DRAW_CALL_REGULAR:
5832e5c31af7Sopenharmony_ci		result = "glDrawArrays()";
5833e5c31af7Sopenharmony_ci		break;
5834e5c31af7Sopenharmony_ci	case DRAW_CALL_REGULAR_INDIRECT:
5835e5c31af7Sopenharmony_ci		result = "glDrawArraysIndirect()";
5836e5c31af7Sopenharmony_ci		break;
5837e5c31af7Sopenharmony_ci	case DRAW_CALL_REGULAR_INDIRECT_MULTI:
5838e5c31af7Sopenharmony_ci		result = "glMultiDrawArraysIndirect()";
5839e5c31af7Sopenharmony_ci		break;
5840e5c31af7Sopenharmony_ci	case DRAW_CALL_REGULAR_INSTANCED:
5841e5c31af7Sopenharmony_ci		result = "glDrawArraysInstanced()";
5842e5c31af7Sopenharmony_ci		break;
5843e5c31af7Sopenharmony_ci	case DRAW_CALL_REGULAR_INSTANCED_BASE_INSTANCE:
5844e5c31af7Sopenharmony_ci		result = "glDrawArraysInstancedBaseInstance()";
5845e5c31af7Sopenharmony_ci		break;
5846e5c31af7Sopenharmony_ci	case DRAW_CALL_REGULAR_MULTI:
5847e5c31af7Sopenharmony_ci		result = "glMultiDrawArrays()";
5848e5c31af7Sopenharmony_ci		break;
5849e5c31af7Sopenharmony_ci
5850e5c31af7Sopenharmony_ci	default:
5851e5c31af7Sopenharmony_ci		break;
5852e5c31af7Sopenharmony_ci	} /* switch (draw_call) */
5853e5c31af7Sopenharmony_ci
5854e5c31af7Sopenharmony_ci	return result;
5855e5c31af7Sopenharmony_ci}
5856e5c31af7Sopenharmony_ci
5857e5c31af7Sopenharmony_ci/** Initializes test data buffer, and then sets up:
5858e5c31af7Sopenharmony_ci *
5859e5c31af7Sopenharmony_ci *  - an immutable buffer object (id stored in m_data_bo), to which the test data
5860e5c31af7Sopenharmony_ci *    is copied.
5861e5c31af7Sopenharmony_ci *  - a mappable immutable buffer object (id stored in m_helper_bo)
5862e5c31af7Sopenharmony_ci **/
5863e5c31af7Sopenharmony_civoid TransformFeedbackBufferStorageTestCase::initDataBO()
5864e5c31af7Sopenharmony_ci{
5865e5c31af7Sopenharmony_ci	initTestData();
5866e5c31af7Sopenharmony_ci
5867e5c31af7Sopenharmony_ci	/* Initialize data BO (the BO which holds index + indirect draw call args */
5868e5c31af7Sopenharmony_ci	DE_ASSERT(m_data_bo == 0);
5869e5c31af7Sopenharmony_ci
5870e5c31af7Sopenharmony_ci	m_gl.genBuffers(1, &m_data_bo);
5871e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
5872e5c31af7Sopenharmony_ci
5873e5c31af7Sopenharmony_ci	m_gl.bindBuffer(GL_ARRAY_BUFFER, m_data_bo);
5874e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
5875e5c31af7Sopenharmony_ci
5876e5c31af7Sopenharmony_ci	m_gl.bufferStorage(GL_ARRAY_BUFFER, m_data_bo_size, DE_NULL, GL_DYNAMIC_STORAGE_BIT);
5877e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed.");
5878e5c31af7Sopenharmony_ci
5879e5c31af7Sopenharmony_ci	m_gl.bufferSubData(GL_ARRAY_BUFFER, m_data_bo_indexed_indirect_arg_offset, m_indirect_arg_data_size,
5880e5c31af7Sopenharmony_ci					   m_indirect_arg_data);
5881e5c31af7Sopenharmony_ci	m_gl.bufferSubData(GL_ARRAY_BUFFER, m_data_bo_index_data_offset, m_index_data_size, m_index_data);
5882e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferSubData() call(s) failed.");
5883e5c31af7Sopenharmony_ci
5884e5c31af7Sopenharmony_ci	/* Generate & bind a helper BO we need to copy the data to from the sparse BO
5885e5c31af7Sopenharmony_ci	 * if direct mapping is not possible.
5886e5c31af7Sopenharmony_ci	 */
5887e5c31af7Sopenharmony_ci	DE_ASSERT(m_result_bo_size != 0);
5888e5c31af7Sopenharmony_ci	DE_ASSERT(m_result_bo == 0);
5889e5c31af7Sopenharmony_ci	DE_ASSERT(m_helper_bo == 0);
5890e5c31af7Sopenharmony_ci
5891e5c31af7Sopenharmony_ci	m_gl.genBuffers(1, &m_helper_bo);
5892e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
5893e5c31af7Sopenharmony_ci
5894e5c31af7Sopenharmony_ci	m_gl.bindBuffer(GL_ARRAY_BUFFER, m_helper_bo);
5895e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
5896e5c31af7Sopenharmony_ci
5897e5c31af7Sopenharmony_ci	m_gl.bufferStorage(GL_ARRAY_BUFFER, m_result_bo_size, DE_NULL, /* data */
5898e5c31af7Sopenharmony_ci					   GL_MAP_READ_BIT);
5899e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed.");
5900e5c31af7Sopenharmony_ci}
5901e5c31af7Sopenharmony_ci
5902e5c31af7Sopenharmony_ci/** Initializes GL objects used across all test case iterations.
5903e5c31af7Sopenharmony_ci *
5904e5c31af7Sopenharmony_ci *  Called once during BufferStorage test run-time.
5905e5c31af7Sopenharmony_ci */
5906e5c31af7Sopenharmony_cibool TransformFeedbackBufferStorageTestCase::initTestCaseGlobal()
5907e5c31af7Sopenharmony_ci{
5908e5c31af7Sopenharmony_ci	bool result = true;
5909e5c31af7Sopenharmony_ci
5910e5c31af7Sopenharmony_ci	/* Initialize test program object */
5911e5c31af7Sopenharmony_ci	static const char*		  tf_varyings[] = { "instance_id", "vertex_id" };
5912e5c31af7Sopenharmony_ci	static const unsigned int n_tf_varyings = sizeof(tf_varyings) / sizeof(tf_varyings[0]);
5913e5c31af7Sopenharmony_ci	static const char*		  vs_body		= "#version 420 core\n"
5914e5c31af7Sopenharmony_ci								 "\n"
5915e5c31af7Sopenharmony_ci								 "out uint instance_id;\n"
5916e5c31af7Sopenharmony_ci								 "out uint vertex_id;\n"
5917e5c31af7Sopenharmony_ci								 "\n"
5918e5c31af7Sopenharmony_ci								 "void main()\n"
5919e5c31af7Sopenharmony_ci								 "{\n"
5920e5c31af7Sopenharmony_ci								 "    instance_id = gl_InstanceID;\n"
5921e5c31af7Sopenharmony_ci								 "    vertex_id   = gl_VertexID;\n"
5922e5c31af7Sopenharmony_ci								 "}\n";
5923e5c31af7Sopenharmony_ci
5924e5c31af7Sopenharmony_ci	m_po_ia = SparseBufferTestUtilities::createProgram(m_gl, DE_NULL, /* fs_body_parts */
5925e5c31af7Sopenharmony_ci													   0,			  /* n_fs_body_parts */
5926e5c31af7Sopenharmony_ci													   &vs_body, 1,   /* n_vs_body_parts */
5927e5c31af7Sopenharmony_ci													   DE_NULL,		  /* attribute_names */
5928e5c31af7Sopenharmony_ci													   DE_NULL,		  /* attribute_locations */
5929e5c31af7Sopenharmony_ci													   0,			  /* n_attribute_properties */
5930e5c31af7Sopenharmony_ci													   tf_varyings, n_tf_varyings, GL_INTERLEAVED_ATTRIBS);
5931e5c31af7Sopenharmony_ci
5932e5c31af7Sopenharmony_ci	m_po_sa = SparseBufferTestUtilities::createProgram(m_gl, DE_NULL, /* fs_body_parts */
5933e5c31af7Sopenharmony_ci													   0,			  /* n_fs_body_parts */
5934e5c31af7Sopenharmony_ci													   &vs_body, 1,   /* n_vs_body_parts */
5935e5c31af7Sopenharmony_ci													   DE_NULL,		  /* attribute_names */
5936e5c31af7Sopenharmony_ci													   DE_NULL,		  /* attribute_locations */
5937e5c31af7Sopenharmony_ci													   0,			  /* n_attribute_properties */
5938e5c31af7Sopenharmony_ci													   tf_varyings, n_tf_varyings, GL_SEPARATE_ATTRIBS);
5939e5c31af7Sopenharmony_ci
5940e5c31af7Sopenharmony_ci	if (m_po_ia == 0 || m_po_sa == 0)
5941e5c31af7Sopenharmony_ci	{
5942e5c31af7Sopenharmony_ci		result = false;
5943e5c31af7Sopenharmony_ci
5944e5c31af7Sopenharmony_ci		goto end;
5945e5c31af7Sopenharmony_ci	}
5946e5c31af7Sopenharmony_ci
5947e5c31af7Sopenharmony_ci	/* Generate & bind a VAO */
5948e5c31af7Sopenharmony_ci	m_gl.genVertexArrays(1, &m_vao);
5949e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenVertexArrays() call failed.");
5950e5c31af7Sopenharmony_ci
5951e5c31af7Sopenharmony_ci	m_gl.bindVertexArray(m_vao);
5952e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindVertexArray() call failed.");
5953e5c31af7Sopenharmony_ci
5954e5c31af7Sopenharmony_ci	initDataBO();
5955e5c31af7Sopenharmony_ci
5956e5c31af7Sopenharmony_ciend:
5957e5c31af7Sopenharmony_ci	return result;
5958e5c31af7Sopenharmony_ci}
5959e5c31af7Sopenharmony_ci
5960e5c31af7Sopenharmony_ci/** Initializes GL objects which are needed for a single test case iteration.
5961e5c31af7Sopenharmony_ci *
5962e5c31af7Sopenharmony_ci *  deinitTestCaseIteration() will be called after the test case is executed in ::execute()
5963e5c31af7Sopenharmony_ci *  to release these objects.
5964e5c31af7Sopenharmony_ci **/
5965e5c31af7Sopenharmony_cibool TransformFeedbackBufferStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo)
5966e5c31af7Sopenharmony_ci{
5967e5c31af7Sopenharmony_ci	bool result = true;
5968e5c31af7Sopenharmony_ci
5969e5c31af7Sopenharmony_ci	/* Initialize buffer objects used by the test case */
5970e5c31af7Sopenharmony_ci	m_result_bo = sparse_bo;
5971e5c31af7Sopenharmony_ci
5972e5c31af7Sopenharmony_ci	/* Quick check */
5973e5c31af7Sopenharmony_ci	DE_ASSERT(m_data_bo != 0);
5974e5c31af7Sopenharmony_ci
5975e5c31af7Sopenharmony_ci	return result;
5976e5c31af7Sopenharmony_ci}
5977e5c31af7Sopenharmony_ci
5978e5c31af7Sopenharmony_ci/** Sets up client-side data arrays, later uploaded to the test buffer object, used as a source for:
5979e5c31af7Sopenharmony_ci *
5980e5c31af7Sopenharmony_ci *  - index data
5981e5c31af7Sopenharmony_ci *  - indirect draw call arguments
5982e5c31af7Sopenharmony_ci *  - multi draw call arguments
5983e5c31af7Sopenharmony_ci **/
5984e5c31af7Sopenharmony_civoid TransformFeedbackBufferStorageTestCase::initTestData()
5985e5c31af7Sopenharmony_ci{
5986e5c31af7Sopenharmony_ci	/* We need the result data to span across at least m_min_memory_page_span memory pages.
5987e5c31af7Sopenharmony_ci	 * Each vertex outputs 2 * sizeof(int) = 8 bytes of data.
5988e5c31af7Sopenharmony_ci	 *
5989e5c31af7Sopenharmony_ci	 * For simplicity, we assume the number of bytes we calculate here is per instance. */
5990e5c31af7Sopenharmony_ci	m_n_vertices_per_instance = static_cast<unsigned int>((m_page_size * m_min_memory_page_span / (sizeof(int) * 2)));
5991e5c31af7Sopenharmony_ci
5992e5c31af7Sopenharmony_ci	/* Let:
5993e5c31af7Sopenharmony_ci	 *
5994e5c31af7Sopenharmony_ci	 *     index_data_size       = (n of vertices per a single instance) * sizeof(unsigned int)
5995e5c31af7Sopenharmony_ci	 *     indexed_indirect_size = sizeof(glDrawElementsIndirect()      indirect arguments)
5996e5c31af7Sopenharmony_ci	 *     indexed_mdi_size      = sizeof(glMultiDrawElementsIndirect() indirect arguments) * 2 (single instance & multiple instances case)
5997e5c31af7Sopenharmony_ci	 *     regular_indirect_size = sizeof(glDrawArraysIndirect()        indirect arguments)
5998e5c31af7Sopenharmony_ci	 *     regular_mdi_size      = sizeof(glMultiDrawArraysIndirect()   indirect arguments) * 2 (single instance & multiple instances case)
5999e5c31af7Sopenharmony_ci	 *
6000e5c31af7Sopenharmony_ci	 *
6001e5c31af7Sopenharmony_ci	 * The layout we will use for the data buffer is:
6002e5c31af7Sopenharmony_ci	 *
6003e5c31af7Sopenharmony_ci	 * [indexed indirect arg data // Size: indexed_indirect_size bytes]
6004e5c31af7Sopenharmony_ci	 * [indexed MDI arg data      // Size: indexed_mdi_size      bytes]
6005e5c31af7Sopenharmony_ci	 * [regular indirect arg data // Size: regular_indirect_size bytes]
6006e5c31af7Sopenharmony_ci	 * [regular MDI arg data      // Size: regular_mdi_size      bytes]
6007e5c31af7Sopenharmony_ci	 * [index data                // Size: index_data_size       bytes]
6008e5c31af7Sopenharmony_ci	 */
6009e5c31af7Sopenharmony_ci	const unsigned int indexed_indirect_size = sizeof(unsigned int) * 5 /* as per GL spec */;
6010e5c31af7Sopenharmony_ci	const unsigned int indexed_mdi_size		 = sizeof(unsigned int) * 5 /* as per GL spec */ * 2; /* draw calls */
6011e5c31af7Sopenharmony_ci	const unsigned int regular_indirect_size = sizeof(unsigned int) * 4;						  /* as per GL spec */
6012e5c31af7Sopenharmony_ci	const unsigned int regular_mdi_size		 = sizeof(unsigned int) * 4 /* as per GL spec */ * 2; /* draw calls */
6013e5c31af7Sopenharmony_ci
6014e5c31af7Sopenharmony_ci	m_data_bo_indexed_indirect_arg_offset = 0;
6015e5c31af7Sopenharmony_ci	m_data_bo_indexed_mdi_arg_offset	  = m_data_bo_indexed_indirect_arg_offset + indexed_indirect_size;
6016e5c31af7Sopenharmony_ci	m_data_bo_regular_indirect_arg_offset = m_data_bo_indexed_mdi_arg_offset + indexed_mdi_size;
6017e5c31af7Sopenharmony_ci	m_data_bo_regular_mdi_arg_offset	  = m_data_bo_regular_indirect_arg_offset + regular_indirect_size;
6018e5c31af7Sopenharmony_ci	m_data_bo_index_data_offset			  = m_data_bo_regular_mdi_arg_offset + regular_mdi_size;
6019e5c31af7Sopenharmony_ci
6020e5c31af7Sopenharmony_ci	/* Form the index data */
6021e5c31af7Sopenharmony_ci	DE_ASSERT(m_index_data == DE_NULL);
6022e5c31af7Sopenharmony_ci	DE_ASSERT(m_draw_call_firstIndex == sizeof(unsigned int));
6023e5c31af7Sopenharmony_ci
6024e5c31af7Sopenharmony_ci	m_index_data_size = static_cast<glw::GLuint>(
6025e5c31af7Sopenharmony_ci		(1 /* extra index, as per m_draw_call_firstIndex */ + m_n_vertices_per_instance) * sizeof(unsigned int));
6026e5c31af7Sopenharmony_ci	m_index_data = (unsigned int*)new unsigned char[m_index_data_size];
6027e5c31af7Sopenharmony_ci
6028e5c31af7Sopenharmony_ci	for (unsigned int n_index = 0; n_index < m_n_vertices_per_instance + 1; ++n_index)
6029e5c31af7Sopenharmony_ci	{
6030e5c31af7Sopenharmony_ci		m_index_data[n_index] = m_n_vertices_per_instance - n_index;
6031e5c31af7Sopenharmony_ci	} /* for (all available indices) */
6032e5c31af7Sopenharmony_ci
6033e5c31af7Sopenharmony_ci	/* Set multi draw-call arguments */
6034e5c31af7Sopenharmony_ci	m_multidrawcall_basevertex[0] = m_draw_call_baseVertex;
6035e5c31af7Sopenharmony_ci	m_multidrawcall_basevertex[1] = 257;
6036e5c31af7Sopenharmony_ci	m_multidrawcall_count[0]	  = m_n_vertices_per_instance;
6037e5c31af7Sopenharmony_ci	m_multidrawcall_count[1]	  = m_n_vertices_per_instance - 16;
6038e5c31af7Sopenharmony_ci	m_multidrawcall_drawcount	 = 2;
6039e5c31af7Sopenharmony_ci	m_multidrawcall_first[0]	  = 0;
6040e5c31af7Sopenharmony_ci	m_multidrawcall_first[1]	  = m_draw_call_first;
6041e5c31af7Sopenharmony_ci	m_multidrawcall_index[0]	  = (glw::GLvoid*)(intptr_t)m_data_bo_index_data_offset;
6042e5c31af7Sopenharmony_ci	m_multidrawcall_index[1]	  = (glw::GLvoid*)(intptr_t)(m_data_bo_index_data_offset + m_draw_call_firstIndex);
6043e5c31af7Sopenharmony_ci	m_multidrawcall_primcount	 = m_n_instances_to_test;
6044e5c31af7Sopenharmony_ci
6045e5c31af7Sopenharmony_ci	/* Form the indirect data */
6046e5c31af7Sopenharmony_ci	DE_ASSERT(m_indirect_arg_data == DE_NULL);
6047e5c31af7Sopenharmony_ci
6048e5c31af7Sopenharmony_ci	m_indirect_arg_data_size = m_data_bo_index_data_offset - m_data_bo_indexed_indirect_arg_offset;
6049e5c31af7Sopenharmony_ci	m_indirect_arg_data		 = (unsigned int*)new unsigned char[m_indirect_arg_data_size];
6050e5c31af7Sopenharmony_ci
6051e5c31af7Sopenharmony_ci	unsigned int* indirect_arg_data_traveller_ptr = m_indirect_arg_data;
6052e5c31af7Sopenharmony_ci
6053e5c31af7Sopenharmony_ci	/* 1. Indexed indirect arg data */
6054e5c31af7Sopenharmony_ci	DE_ASSERT(((unsigned int)(intptr_t)(m_multidrawcall_index[1]) % sizeof(unsigned int)) == 0);
6055e5c31af7Sopenharmony_ci
6056e5c31af7Sopenharmony_ci	*indirect_arg_data_traveller_ptr = m_multidrawcall_count[1]; /* count */
6057e5c31af7Sopenharmony_ci	indirect_arg_data_traveller_ptr++;
6058e5c31af7Sopenharmony_ci
6059e5c31af7Sopenharmony_ci	*indirect_arg_data_traveller_ptr = m_n_instances_to_test; /* primCount */
6060e5c31af7Sopenharmony_ci	indirect_arg_data_traveller_ptr++;
6061e5c31af7Sopenharmony_ci
6062e5c31af7Sopenharmony_ci	*indirect_arg_data_traveller_ptr = static_cast<unsigned int>((unsigned int)(intptr_t)(m_multidrawcall_index[1]) /
6063e5c31af7Sopenharmony_ci																 sizeof(unsigned int)); /* firstIndex */
6064e5c31af7Sopenharmony_ci	indirect_arg_data_traveller_ptr++;
6065e5c31af7Sopenharmony_ci
6066e5c31af7Sopenharmony_ci	*indirect_arg_data_traveller_ptr = m_draw_call_baseVertex; /* baseVertex */
6067e5c31af7Sopenharmony_ci	indirect_arg_data_traveller_ptr++;
6068e5c31af7Sopenharmony_ci
6069e5c31af7Sopenharmony_ci	*indirect_arg_data_traveller_ptr = m_draw_call_baseInstance; /* baseInstance */
6070e5c31af7Sopenharmony_ci	indirect_arg_data_traveller_ptr++;
6071e5c31af7Sopenharmony_ci
6072e5c31af7Sopenharmony_ci	/* 2. Indexed MDI arg data */
6073e5c31af7Sopenharmony_ci	for (unsigned int n_draw_call = 0; n_draw_call < 2; ++n_draw_call)
6074e5c31af7Sopenharmony_ci	{
6075e5c31af7Sopenharmony_ci		DE_ASSERT(((unsigned int)(intptr_t)(m_multidrawcall_index[n_draw_call]) % sizeof(unsigned int)) == 0);
6076e5c31af7Sopenharmony_ci
6077e5c31af7Sopenharmony_ci		*indirect_arg_data_traveller_ptr = m_multidrawcall_count[n_draw_call]; /* count */
6078e5c31af7Sopenharmony_ci		indirect_arg_data_traveller_ptr++;
6079e5c31af7Sopenharmony_ci
6080e5c31af7Sopenharmony_ci		*indirect_arg_data_traveller_ptr = (n_draw_call == 0) ? 1 : m_n_instances_to_test; /* primCount */
6081e5c31af7Sopenharmony_ci		indirect_arg_data_traveller_ptr++;
6082e5c31af7Sopenharmony_ci
6083e5c31af7Sopenharmony_ci		*indirect_arg_data_traveller_ptr = static_cast<unsigned int>(
6084e5c31af7Sopenharmony_ci			(unsigned int)(intptr_t)(m_multidrawcall_index[n_draw_call]) / sizeof(unsigned int)); /* firstIndex */
6085e5c31af7Sopenharmony_ci		indirect_arg_data_traveller_ptr++;
6086e5c31af7Sopenharmony_ci
6087e5c31af7Sopenharmony_ci		*indirect_arg_data_traveller_ptr = m_draw_call_baseVertex;
6088e5c31af7Sopenharmony_ci		indirect_arg_data_traveller_ptr++;
6089e5c31af7Sopenharmony_ci
6090e5c31af7Sopenharmony_ci		*indirect_arg_data_traveller_ptr = m_draw_call_baseInstance;
6091e5c31af7Sopenharmony_ci		indirect_arg_data_traveller_ptr++;
6092e5c31af7Sopenharmony_ci	} /* for (both single-instanced and multi-instanced cases) */
6093e5c31af7Sopenharmony_ci
6094e5c31af7Sopenharmony_ci	/* 3. Regular indirect arg data */
6095e5c31af7Sopenharmony_ci	*indirect_arg_data_traveller_ptr = m_multidrawcall_count[1]; /* count */
6096e5c31af7Sopenharmony_ci	indirect_arg_data_traveller_ptr++;
6097e5c31af7Sopenharmony_ci
6098e5c31af7Sopenharmony_ci	*indirect_arg_data_traveller_ptr = m_n_instances_to_test; /* primCount */
6099e5c31af7Sopenharmony_ci	indirect_arg_data_traveller_ptr++;
6100e5c31af7Sopenharmony_ci
6101e5c31af7Sopenharmony_ci	*indirect_arg_data_traveller_ptr = m_draw_call_first; /* first */
6102e5c31af7Sopenharmony_ci	indirect_arg_data_traveller_ptr++;
6103e5c31af7Sopenharmony_ci
6104e5c31af7Sopenharmony_ci	*indirect_arg_data_traveller_ptr = m_draw_call_baseInstance; /* baseInstance */
6105e5c31af7Sopenharmony_ci	indirect_arg_data_traveller_ptr++;
6106e5c31af7Sopenharmony_ci
6107e5c31af7Sopenharmony_ci	/* 4. Regular MDI arg data */
6108e5c31af7Sopenharmony_ci	for (unsigned int n_draw_call = 0; n_draw_call < 2; ++n_draw_call)
6109e5c31af7Sopenharmony_ci	{
6110e5c31af7Sopenharmony_ci		*indirect_arg_data_traveller_ptr = m_multidrawcall_count[n_draw_call]; /* count */
6111e5c31af7Sopenharmony_ci		indirect_arg_data_traveller_ptr++;
6112e5c31af7Sopenharmony_ci
6113e5c31af7Sopenharmony_ci		*indirect_arg_data_traveller_ptr = (n_draw_call == 0) ? 1 : m_n_instances_to_test; /* instanceCount */
6114e5c31af7Sopenharmony_ci		indirect_arg_data_traveller_ptr++;
6115e5c31af7Sopenharmony_ci
6116e5c31af7Sopenharmony_ci		*indirect_arg_data_traveller_ptr = m_draw_call_first; /* first */
6117e5c31af7Sopenharmony_ci		indirect_arg_data_traveller_ptr++;
6118e5c31af7Sopenharmony_ci
6119e5c31af7Sopenharmony_ci		*indirect_arg_data_traveller_ptr = m_draw_call_baseInstance; /* baseInstance */
6120e5c31af7Sopenharmony_ci		indirect_arg_data_traveller_ptr++;
6121e5c31af7Sopenharmony_ci	} /* for (both single-instanced and multi-instanced cases) */
6122e5c31af7Sopenharmony_ci
6123e5c31af7Sopenharmony_ci	/* Store the number of bytes we will need to allocate for the data BO */
6124e5c31af7Sopenharmony_ci	m_data_bo_size = m_index_data_size + m_indirect_arg_data_size;
6125e5c31af7Sopenharmony_ci
6126e5c31af7Sopenharmony_ci	/* Determine the number of bytes we will need to have at hand to hold all the captured TF varyings.
6127e5c31af7Sopenharmony_ci	 * The equation below takes into account the heaviest draw call the test will ever issue.
6128e5c31af7Sopenharmony_ci	 */
6129e5c31af7Sopenharmony_ci	m_result_bo_size =
6130e5c31af7Sopenharmony_ci		static_cast<glw::GLuint>(sizeof(unsigned int) * 2 /* TF varyings per vertex */ *
6131e5c31af7Sopenharmony_ci								 (m_multidrawcall_count[0] + m_multidrawcall_count[1]) * m_multidrawcall_primcount);
6132e5c31af7Sopenharmony_ci	m_result_bo_size_rounded = SparseBufferTestUtilities::alignOffset(m_result_bo_size, m_page_size);
6133e5c31af7Sopenharmony_ci
6134e5c31af7Sopenharmony_ci	/* Quick checks */
6135e5c31af7Sopenharmony_ci	DE_ASSERT(m_min_memory_page_span > 0);
6136e5c31af7Sopenharmony_ci	DE_ASSERT(m_page_size > 0);
6137e5c31af7Sopenharmony_ci	DE_ASSERT(m_result_bo_size >= (m_min_memory_page_span * m_page_size));
6138e5c31af7Sopenharmony_ci}
6139e5c31af7Sopenharmony_ci
6140e5c31af7Sopenharmony_ci/** Constructor.
6141e5c31af7Sopenharmony_ci *
6142e5c31af7Sopenharmony_ci *  @param gl                         GL entry-points container
6143e5c31af7Sopenharmony_ci *  @param testContext                CTS test context
6144e5c31af7Sopenharmony_ci *  @param page_size                  Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query.
6145e5c31af7Sopenharmony_ci *  @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point.
6146e5c31af7Sopenharmony_ci */
6147e5c31af7Sopenharmony_ciUniformBufferStorageTestCase::UniformBufferStorageTestCase(const glw::Functions& gl, tcu::TestContext& testContext,
6148e5c31af7Sopenharmony_ci														   glw::GLint page_size)
6149e5c31af7Sopenharmony_ci	: m_gl(gl)
6150e5c31af7Sopenharmony_ci	, m_gl_uniform_buffer_offset_alignment_value(0)
6151e5c31af7Sopenharmony_ci	, m_helper_bo(0)
6152e5c31af7Sopenharmony_ci	, m_n_pages_to_use(4)
6153e5c31af7Sopenharmony_ci	, m_n_ubo_uints(0)
6154e5c31af7Sopenharmony_ci	, m_page_size(page_size)
6155e5c31af7Sopenharmony_ci	, m_po(0)
6156e5c31af7Sopenharmony_ci	, m_sparse_bo(0)
6157e5c31af7Sopenharmony_ci	, m_sparse_bo_data_size(0)
6158e5c31af7Sopenharmony_ci	, m_sparse_bo_data_start_offset(0)
6159e5c31af7Sopenharmony_ci	, m_sparse_bo_size(0)
6160e5c31af7Sopenharmony_ci	, m_sparse_bo_size_rounded(0)
6161e5c31af7Sopenharmony_ci	, m_testCtx(testContext)
6162e5c31af7Sopenharmony_ci	, m_tf_bo(0)
6163e5c31af7Sopenharmony_ci	, m_ubo_data(DE_NULL)
6164e5c31af7Sopenharmony_ci	, m_vao(0)
6165e5c31af7Sopenharmony_ci{
6166e5c31af7Sopenharmony_ci	if ((m_n_pages_to_use % 2) != 0)
6167e5c31af7Sopenharmony_ci	{
6168e5c31af7Sopenharmony_ci		DE_ASSERT(DE_FALSE);
6169e5c31af7Sopenharmony_ci	}
6170e5c31af7Sopenharmony_ci}
6171e5c31af7Sopenharmony_ci
6172e5c31af7Sopenharmony_ci/** Releases all GL objects used across all test case iterations.
6173e5c31af7Sopenharmony_ci *
6174e5c31af7Sopenharmony_ci *  Called once during BufferStorage test run-time.
6175e5c31af7Sopenharmony_ci */
6176e5c31af7Sopenharmony_civoid UniformBufferStorageTestCase::deinitTestCaseGlobal()
6177e5c31af7Sopenharmony_ci{
6178e5c31af7Sopenharmony_ci	if (m_helper_bo != 0)
6179e5c31af7Sopenharmony_ci	{
6180e5c31af7Sopenharmony_ci		m_gl.deleteBuffers(1, &m_helper_bo);
6181e5c31af7Sopenharmony_ci
6182e5c31af7Sopenharmony_ci		m_helper_bo = 0;
6183e5c31af7Sopenharmony_ci	}
6184e5c31af7Sopenharmony_ci
6185e5c31af7Sopenharmony_ci	if (m_po != 0)
6186e5c31af7Sopenharmony_ci	{
6187e5c31af7Sopenharmony_ci		m_gl.deleteProgram(m_po);
6188e5c31af7Sopenharmony_ci
6189e5c31af7Sopenharmony_ci		m_po = 0;
6190e5c31af7Sopenharmony_ci	}
6191e5c31af7Sopenharmony_ci
6192e5c31af7Sopenharmony_ci	if (m_tf_bo != 0)
6193e5c31af7Sopenharmony_ci	{
6194e5c31af7Sopenharmony_ci		m_gl.deleteBuffers(1, &m_tf_bo);
6195e5c31af7Sopenharmony_ci
6196e5c31af7Sopenharmony_ci		m_tf_bo = 0;
6197e5c31af7Sopenharmony_ci	}
6198e5c31af7Sopenharmony_ci
6199e5c31af7Sopenharmony_ci	if (m_ubo_data != DE_NULL)
6200e5c31af7Sopenharmony_ci	{
6201e5c31af7Sopenharmony_ci		delete[] m_ubo_data;
6202e5c31af7Sopenharmony_ci
6203e5c31af7Sopenharmony_ci		m_ubo_data = DE_NULL;
6204e5c31af7Sopenharmony_ci	}
6205e5c31af7Sopenharmony_ci
6206e5c31af7Sopenharmony_ci	if (m_vao != 0)
6207e5c31af7Sopenharmony_ci	{
6208e5c31af7Sopenharmony_ci		m_gl.deleteVertexArrays(1, &m_vao);
6209e5c31af7Sopenharmony_ci
6210e5c31af7Sopenharmony_ci		m_vao = 0;
6211e5c31af7Sopenharmony_ci	}
6212e5c31af7Sopenharmony_ci}
6213e5c31af7Sopenharmony_ci
6214e5c31af7Sopenharmony_ci/** Releases temporary GL objects, created specifically for one test case iteration. */
6215e5c31af7Sopenharmony_civoid UniformBufferStorageTestCase::deinitTestCaseIteration()
6216e5c31af7Sopenharmony_ci{
6217e5c31af7Sopenharmony_ci	if (m_sparse_bo != 0)
6218e5c31af7Sopenharmony_ci	{
6219e5c31af7Sopenharmony_ci		m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
6220e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
6221e5c31af7Sopenharmony_ci
6222e5c31af7Sopenharmony_ci		m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,				  /* offset */
6223e5c31af7Sopenharmony_ci									 m_sparse_bo_size_rounded, GL_FALSE); /* commit */
6224e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
6225e5c31af7Sopenharmony_ci
6226e5c31af7Sopenharmony_ci		m_sparse_bo = 0;
6227e5c31af7Sopenharmony_ci	}
6228e5c31af7Sopenharmony_ci}
6229e5c31af7Sopenharmony_ci
6230e5c31af7Sopenharmony_ci/** Executes a single test iteration. The BufferStorage test will call this method
6231e5c31af7Sopenharmony_ci *  numerously during its life-time, testing various valid flag combinations applied
6232e5c31af7Sopenharmony_ci *  to the tested sparse buffer object at glBufferStorage() call time.
6233e5c31af7Sopenharmony_ci *
6234e5c31af7Sopenharmony_ci *  @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage()
6235e5c31af7Sopenharmony_ci *                                 call to set up the sparse buffer's storage.
6236e5c31af7Sopenharmony_ci *
6237e5c31af7Sopenharmony_ci *  @return true if the test case executed correctly, false otherwise.
6238e5c31af7Sopenharmony_ci */
6239e5c31af7Sopenharmony_cibool UniformBufferStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags)
6240e5c31af7Sopenharmony_ci{
6241e5c31af7Sopenharmony_ci	(void)sparse_bo_storage_flags;
6242e5c31af7Sopenharmony_ci	bool result = true;
6243e5c31af7Sopenharmony_ci
6244e5c31af7Sopenharmony_ci	m_gl.bindBufferRange(GL_UNIFORM_BUFFER, 0, /* index */
6245e5c31af7Sopenharmony_ci						 m_sparse_bo, m_sparse_bo_data_start_offset, m_n_ubo_uints * 4 * sizeof(unsigned int));
6246e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBufferBase() call failed.");
6247e5c31af7Sopenharmony_ci
6248e5c31af7Sopenharmony_ci	/* Run the test in three iterations:
6249e5c31af7Sopenharmony_ci	 *
6250e5c31af7Sopenharmony_ci	 * 1) Whole UBO storage is backed by physical backing.
6251e5c31af7Sopenharmony_ci	 * 2) Half the UBO storage is backed by physical backing.
6252e5c31af7Sopenharmony_ci	 * 3) None of the UBO storage is backed by physical backing.
6253e5c31af7Sopenharmony_ci	 */
6254e5c31af7Sopenharmony_ci	for (unsigned int n_iteration = 0; n_iteration < 3; ++n_iteration)
6255e5c31af7Sopenharmony_ci	{
6256e5c31af7Sopenharmony_ci		bool		 result_local			 = true;
6257e5c31af7Sopenharmony_ci		unsigned int ubo_commit_size		 = 0;
6258e5c31af7Sopenharmony_ci		unsigned int ubo_commit_start_offset = 0;
6259e5c31af7Sopenharmony_ci
6260e5c31af7Sopenharmony_ci		switch (n_iteration)
6261e5c31af7Sopenharmony_ci		{
6262e5c31af7Sopenharmony_ci		case 0:
6263e5c31af7Sopenharmony_ci		{
6264e5c31af7Sopenharmony_ci			ubo_commit_size			= m_sparse_bo_data_size;
6265e5c31af7Sopenharmony_ci			ubo_commit_start_offset = m_sparse_bo_data_start_offset;
6266e5c31af7Sopenharmony_ci
6267e5c31af7Sopenharmony_ci			break;
6268e5c31af7Sopenharmony_ci		}
6269e5c31af7Sopenharmony_ci
6270e5c31af7Sopenharmony_ci		case 1:
6271e5c31af7Sopenharmony_ci		{
6272e5c31af7Sopenharmony_ci			DE_ASSERT((m_sparse_bo_data_size % 2) == 0);
6273e5c31af7Sopenharmony_ci			DE_ASSERT((m_sparse_bo_data_size % m_page_size) == 0);
6274e5c31af7Sopenharmony_ci
6275e5c31af7Sopenharmony_ci			ubo_commit_size			= m_sparse_bo_data_size / 2;
6276e5c31af7Sopenharmony_ci			ubo_commit_start_offset = m_sparse_bo_data_start_offset;
6277e5c31af7Sopenharmony_ci
6278e5c31af7Sopenharmony_ci			break;
6279e5c31af7Sopenharmony_ci		}
6280e5c31af7Sopenharmony_ci
6281e5c31af7Sopenharmony_ci		case 2:
6282e5c31af7Sopenharmony_ci		{
6283e5c31af7Sopenharmony_ci			/* The default values do just fine */
6284e5c31af7Sopenharmony_ci
6285e5c31af7Sopenharmony_ci			break;
6286e5c31af7Sopenharmony_ci		}
6287e5c31af7Sopenharmony_ci
6288e5c31af7Sopenharmony_ci		default:
6289e5c31af7Sopenharmony_ci		{
6290e5c31af7Sopenharmony_ci			TCU_FAIL("Invalid iteration index");
6291e5c31af7Sopenharmony_ci		}
6292e5c31af7Sopenharmony_ci		} /* switch (n_iteration) */
6293e5c31af7Sopenharmony_ci
6294e5c31af7Sopenharmony_ci		m_gl.bufferPageCommitmentARB(GL_UNIFORM_BUFFER, ubo_commit_start_offset, ubo_commit_size, GL_TRUE); /* commit */
6295e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
6296e5c31af7Sopenharmony_ci
6297e5c31af7Sopenharmony_ci		/* Copy the UBO data */
6298e5c31af7Sopenharmony_ci		m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, /* readOffset */
6299e5c31af7Sopenharmony_ci							   ubo_commit_start_offset, ubo_commit_size);
6300e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
6301e5c31af7Sopenharmony_ci
6302e5c31af7Sopenharmony_ci		/* Issue the draw call to execute the test */
6303e5c31af7Sopenharmony_ci		m_gl.useProgram(m_po);
6304e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() call failed.");
6305e5c31af7Sopenharmony_ci
6306e5c31af7Sopenharmony_ci		m_gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_tf_bo);
6307e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
6308e5c31af7Sopenharmony_ci
6309e5c31af7Sopenharmony_ci		m_gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* index */
6310e5c31af7Sopenharmony_ci							m_tf_bo);
6311e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBufferBase() call failed.");
6312e5c31af7Sopenharmony_ci
6313e5c31af7Sopenharmony_ci		m_gl.beginTransformFeedback(GL_POINTS);
6314e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBeginTransformFeedback() call failed.");
6315e5c31af7Sopenharmony_ci
6316e5c31af7Sopenharmony_ci		m_gl.drawArrays(GL_POINTS, 0, /* first */
6317e5c31af7Sopenharmony_ci						m_n_ubo_uints);
6318e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArrays() call failed.");
6319e5c31af7Sopenharmony_ci
6320e5c31af7Sopenharmony_ci		m_gl.endTransformFeedback();
6321e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glEndTransformFeedback() call failed.");
6322e5c31af7Sopenharmony_ci
6323e5c31af7Sopenharmony_ci		/* Retrieve the data, verify the output */
6324e5c31af7Sopenharmony_ci		const unsigned int* result_data_ptr =
6325e5c31af7Sopenharmony_ci			(const unsigned int*)m_gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
6326e5c31af7Sopenharmony_ci		unsigned int ubo_data_offset = m_sparse_bo_data_start_offset;
6327e5c31af7Sopenharmony_ci
6328e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMapBuffer() call failed.");
6329e5c31af7Sopenharmony_ci
6330e5c31af7Sopenharmony_ci		for (unsigned int n_vertex = 0; n_vertex < m_n_ubo_uints && result_local;
6331e5c31af7Sopenharmony_ci			 ++n_vertex, ubo_data_offset = static_cast<unsigned int>(ubo_data_offset + 4 * sizeof(unsigned int)))
6332e5c31af7Sopenharmony_ci		{
6333e5c31af7Sopenharmony_ci			const bool is_ub_data_physically_backed = (ubo_data_offset >= ubo_commit_start_offset &&
6334e5c31af7Sopenharmony_ci													   ubo_data_offset < (ubo_commit_start_offset + ubo_commit_size)) ?
6335e5c31af7Sopenharmony_ci														  1 :
6336e5c31af7Sopenharmony_ci														  0;
6337e5c31af7Sopenharmony_ci			unsigned int	   expected_value  = -1;
6338e5c31af7Sopenharmony_ci			const unsigned int retrieved_value = result_data_ptr[n_vertex];
6339e5c31af7Sopenharmony_ci
6340e5c31af7Sopenharmony_ci			if (is_ub_data_physically_backed)
6341e5c31af7Sopenharmony_ci			{
6342e5c31af7Sopenharmony_ci				expected_value = 1;
6343e5c31af7Sopenharmony_ci			}
6344e5c31af7Sopenharmony_ci			else
6345e5c31af7Sopenharmony_ci			{
6346e5c31af7Sopenharmony_ci				/* Read ops applied against non-committed sparse buffers return an undefined value.
6347e5c31af7Sopenharmony_ci				 */
6348e5c31af7Sopenharmony_ci				continue;
6349e5c31af7Sopenharmony_ci			}
6350e5c31af7Sopenharmony_ci
6351e5c31af7Sopenharmony_ci			if (expected_value != retrieved_value)
6352e5c31af7Sopenharmony_ci			{
6353e5c31af7Sopenharmony_ci				m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value "
6354e5c31af7Sopenharmony_ci															   "("
6355e5c31af7Sopenharmony_ci								   << retrieved_value << ") "
6356e5c31af7Sopenharmony_ci														 "found at index "
6357e5c31af7Sopenharmony_ci														 "("
6358e5c31af7Sopenharmony_ci								   << n_vertex << ")"
6359e5c31af7Sopenharmony_ci												  ", instead of the expected value "
6360e5c31af7Sopenharmony_ci												  "("
6361e5c31af7Sopenharmony_ci								   << expected_value << ")"
6362e5c31af7Sopenharmony_ci														". Iteration index:"
6363e5c31af7Sopenharmony_ci														"("
6364e5c31af7Sopenharmony_ci								   << n_iteration << ")" << tcu::TestLog::EndMessage;
6365e5c31af7Sopenharmony_ci
6366e5c31af7Sopenharmony_ci				result_local = false;
6367e5c31af7Sopenharmony_ci			}
6368e5c31af7Sopenharmony_ci		}
6369e5c31af7Sopenharmony_ci
6370e5c31af7Sopenharmony_ci		result &= result_local;
6371e5c31af7Sopenharmony_ci
6372e5c31af7Sopenharmony_ci		/* Clean up in anticipation for the next iteration */
6373e5c31af7Sopenharmony_ci		static const unsigned char data_zero_r8 = 0;
6374e5c31af7Sopenharmony_ci
6375e5c31af7Sopenharmony_ci		m_gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
6376e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUnmapBuffer() call failed.");
6377e5c31af7Sopenharmony_ci
6378e5c31af7Sopenharmony_ci		m_gl.clearBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, GL_R8, GL_RED, GL_UNSIGNED_BYTE, &data_zero_r8);
6379e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glClearBufferData() call failed.");
6380e5c31af7Sopenharmony_ci
6381e5c31af7Sopenharmony_ci		m_gl.bufferPageCommitmentARB(GL_UNIFORM_BUFFER, 0, m_sparse_bo_size_rounded, GL_FALSE); /* commit */
6382e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
6383e5c31af7Sopenharmony_ci	} /* for (all three iterations) */
6384e5c31af7Sopenharmony_ci
6385e5c31af7Sopenharmony_ci	return result;
6386e5c31af7Sopenharmony_ci}
6387e5c31af7Sopenharmony_ci
6388e5c31af7Sopenharmony_ci/** Initializes GL objects used across all test case iterations.
6389e5c31af7Sopenharmony_ci *
6390e5c31af7Sopenharmony_ci *  Called once during BufferStorage test run-time.
6391e5c31af7Sopenharmony_ci */
6392e5c31af7Sopenharmony_cibool UniformBufferStorageTestCase::initTestCaseGlobal()
6393e5c31af7Sopenharmony_ci{
6394e5c31af7Sopenharmony_ci	/* Cache GL constant values */
6395e5c31af7Sopenharmony_ci	glw::GLint gl_max_uniform_block_size_value = 0;
6396e5c31af7Sopenharmony_ci
6397e5c31af7Sopenharmony_ci	m_gl.getIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &gl_max_uniform_block_size_value);
6398e5c31af7Sopenharmony_ci	m_gl.getIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &m_gl_uniform_buffer_offset_alignment_value);
6399e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetIntegerv() call(s) failed.");
6400e5c31af7Sopenharmony_ci
6401e5c31af7Sopenharmony_ci	/* Determine the number of uints we can access at once from a single VS invocation */
6402e5c31af7Sopenharmony_ci	DE_ASSERT(gl_max_uniform_block_size_value >= 1);
6403e5c31af7Sopenharmony_ci
6404e5c31af7Sopenharmony_ci	/* Account for the fact that in std140 layout, array elements will be rounded up
6405e5c31af7Sopenharmony_ci	 * to the size of a vec4, i.e. 16 bytes. */
6406e5c31af7Sopenharmony_ci	m_n_ubo_uints = static_cast<unsigned int>(gl_max_uniform_block_size_value / (4 * sizeof(unsigned int)));
6407e5c31af7Sopenharmony_ci
6408e5c31af7Sopenharmony_ci	/* Prepare the test program */
6409e5c31af7Sopenharmony_ci	std::stringstream vs_body_define_sstream;
6410e5c31af7Sopenharmony_ci	std::string		  vs_body_define_string;
6411e5c31af7Sopenharmony_ci
6412e5c31af7Sopenharmony_ci	const char* tf_varying		 = "result";
6413e5c31af7Sopenharmony_ci	const char* vs_body_preamble = "#version 140\n"
6414e5c31af7Sopenharmony_ci								   "\n";
6415e5c31af7Sopenharmony_ci
6416e5c31af7Sopenharmony_ci	const char* vs_body_main = "\n"
6417e5c31af7Sopenharmony_ci							   "layout(std140) uniform data\n"
6418e5c31af7Sopenharmony_ci							   "{\n"
6419e5c31af7Sopenharmony_ci							   "    uint data_input[N_UBO_UINTS];"
6420e5c31af7Sopenharmony_ci							   "};\n"
6421e5c31af7Sopenharmony_ci							   "\n"
6422e5c31af7Sopenharmony_ci							   "out uint result;\n"
6423e5c31af7Sopenharmony_ci							   "\n"
6424e5c31af7Sopenharmony_ci							   "void main()\n"
6425e5c31af7Sopenharmony_ci							   "{\n"
6426e5c31af7Sopenharmony_ci							   "    result = (data_input[gl_VertexID] == uint(gl_VertexID) ) ? 1u : 0u;\n"
6427e5c31af7Sopenharmony_ci							   "}";
6428e5c31af7Sopenharmony_ci
6429e5c31af7Sopenharmony_ci	vs_body_define_sstream << "#define N_UBO_UINTS (" << m_n_ubo_uints << ")\n";
6430e5c31af7Sopenharmony_ci	vs_body_define_string = vs_body_define_sstream.str();
6431e5c31af7Sopenharmony_ci
6432e5c31af7Sopenharmony_ci	const char*		   vs_body_parts[] = { vs_body_preamble, vs_body_define_string.c_str(), vs_body_main };
6433e5c31af7Sopenharmony_ci	const unsigned int n_vs_body_parts = sizeof(vs_body_parts) / sizeof(vs_body_parts[0]);
6434e5c31af7Sopenharmony_ci
6435e5c31af7Sopenharmony_ci	m_po = SparseBufferTestUtilities::createProgram(m_gl, DE_NULL,							 /* fs_body_parts */
6436e5c31af7Sopenharmony_ci													0,										 /* n_fs_body_parts */
6437e5c31af7Sopenharmony_ci													vs_body_parts, n_vs_body_parts, DE_NULL, /* attribute_names */
6438e5c31af7Sopenharmony_ci													DE_NULL,								 /* attribute_locations */
6439e5c31af7Sopenharmony_ci													0,				/* n_attribute_properties */
6440e5c31af7Sopenharmony_ci													&tf_varying, 1, /* n_tf_varyings */
6441e5c31af7Sopenharmony_ci													GL_INTERLEAVED_ATTRIBS);
6442e5c31af7Sopenharmony_ci
6443e5c31af7Sopenharmony_ci	if (m_po == 0)
6444e5c31af7Sopenharmony_ci	{
6445e5c31af7Sopenharmony_ci		TCU_FAIL("The test program failed to link");
6446e5c31af7Sopenharmony_ci	}
6447e5c31af7Sopenharmony_ci
6448e5c31af7Sopenharmony_ci	/* Determine the number of bytes the sparse buffer needs to be able to have
6449e5c31af7Sopenharmony_ci	 * a physical backing or.
6450e5c31af7Sopenharmony_ci	 *
6451e5c31af7Sopenharmony_ci	 * We will provide physical backing for twice the required size and then use
6452e5c31af7Sopenharmony_ci	 * a region in the centered of the allocated memory block.
6453e5c31af7Sopenharmony_ci	 *
6454e5c31af7Sopenharmony_ci	 * NOTE: We need to be able to use an offset which is aligned to both the page size,
6455e5c31af7Sopenharmony_ci	 *       and the UB offset alignment.
6456e5c31af7Sopenharmony_ci	 * */
6457e5c31af7Sopenharmony_ci	m_sparse_bo_data_size = static_cast<unsigned int>(sizeof(unsigned int) * m_page_size);
6458e5c31af7Sopenharmony_ci	m_sparse_bo_size	  = (m_page_size * m_gl_uniform_buffer_offset_alignment_value) * 2;
6459e5c31af7Sopenharmony_ci
6460e5c31af7Sopenharmony_ci	if (m_sparse_bo_size < m_sparse_bo_data_size * 2)
6461e5c31af7Sopenharmony_ci	{
6462e5c31af7Sopenharmony_ci		m_sparse_bo_size = m_sparse_bo_data_size * 2;
6463e5c31af7Sopenharmony_ci	}
6464e5c31af7Sopenharmony_ci
6465e5c31af7Sopenharmony_ci	m_sparse_bo_size_rounded	  = m_sparse_bo_size; /* rounded to the page size by default */
6466e5c31af7Sopenharmony_ci	m_sparse_bo_data_start_offset = (m_sparse_bo_size - m_sparse_bo_data_size) / 2;
6467e5c31af7Sopenharmony_ci
6468e5c31af7Sopenharmony_ci	/* Set up the TFBO storage */
6469e5c31af7Sopenharmony_ci	const unsigned tfbo_size = static_cast<unsigned int>(sizeof(unsigned int) * m_n_ubo_uints);
6470e5c31af7Sopenharmony_ci
6471e5c31af7Sopenharmony_ci	m_gl.genBuffers(1, &m_tf_bo);
6472e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
6473e5c31af7Sopenharmony_ci
6474e5c31af7Sopenharmony_ci	m_gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_tf_bo);
6475e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
6476e5c31af7Sopenharmony_ci
6477e5c31af7Sopenharmony_ci	m_gl.bufferStorage(GL_TRANSFORM_FEEDBACK_BUFFER, tfbo_size, DE_NULL, /* data */
6478e5c31af7Sopenharmony_ci					   GL_MAP_READ_BIT);
6479e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed.");
6480e5c31af7Sopenharmony_ci
6481e5c31af7Sopenharmony_ci	/* Set up the UBO contents. We're actually setting up an immutable BO here,
6482e5c31af7Sopenharmony_ci	 * but we'll use its contents for a copy op, executed at the beginning of
6483e5c31af7Sopenharmony_ci	 * each iteration.
6484e5c31af7Sopenharmony_ci	 */
6485e5c31af7Sopenharmony_ci	unsigned int* ubo_data_traveller_ptr = DE_NULL;
6486e5c31af7Sopenharmony_ci
6487e5c31af7Sopenharmony_ci	DE_ASSERT((m_sparse_bo_data_size % sizeof(unsigned int)) == 0);
6488e5c31af7Sopenharmony_ci
6489e5c31af7Sopenharmony_ci	m_ubo_data			   = new (std::nothrow) unsigned char[m_sparse_bo_data_size];
6490e5c31af7Sopenharmony_ci	ubo_data_traveller_ptr = (unsigned int*)m_ubo_data;
6491e5c31af7Sopenharmony_ci
6492e5c31af7Sopenharmony_ci	for (unsigned int n_vertex = 0; n_vertex < m_sparse_bo_data_size / (4 * sizeof(unsigned int)); ++n_vertex)
6493e5c31af7Sopenharmony_ci	{
6494e5c31af7Sopenharmony_ci		*ubo_data_traveller_ptr = n_vertex;
6495e5c31af7Sopenharmony_ci		ubo_data_traveller_ptr += 4;
6496e5c31af7Sopenharmony_ci	}
6497e5c31af7Sopenharmony_ci
6498e5c31af7Sopenharmony_ci	m_gl.genBuffers(1, &m_helper_bo);
6499e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
6500e5c31af7Sopenharmony_ci
6501e5c31af7Sopenharmony_ci	m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
6502e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
6503e5c31af7Sopenharmony_ci
6504e5c31af7Sopenharmony_ci	/* Set up helper BO storage */
6505e5c31af7Sopenharmony_ci	m_gl.bufferStorage(GL_COPY_READ_BUFFER, m_sparse_bo_data_size, m_ubo_data, 0); /* flags */
6506e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed.");
6507e5c31af7Sopenharmony_ci
6508e5c31af7Sopenharmony_ci	/* Set up the VAO */
6509e5c31af7Sopenharmony_ci	m_gl.genVertexArrays(1, &m_vao);
6510e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenVertexArrays() call failed.");
6511e5c31af7Sopenharmony_ci
6512e5c31af7Sopenharmony_ci	m_gl.bindVertexArray(m_vao);
6513e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindVertexArray() call failed.");
6514e5c31af7Sopenharmony_ci
6515e5c31af7Sopenharmony_ci	return true;
6516e5c31af7Sopenharmony_ci}
6517e5c31af7Sopenharmony_ci
6518e5c31af7Sopenharmony_ci/** Initializes GL objects which are needed for a single test case iteration.
6519e5c31af7Sopenharmony_ci *
6520e5c31af7Sopenharmony_ci *  deinitTestCaseIteration() will be called after the test case is executed in ::execute()
6521e5c31af7Sopenharmony_ci *  to release these objects.
6522e5c31af7Sopenharmony_ci **/
6523e5c31af7Sopenharmony_cibool UniformBufferStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo)
6524e5c31af7Sopenharmony_ci{
6525e5c31af7Sopenharmony_ci	bool result = true;
6526e5c31af7Sopenharmony_ci
6527e5c31af7Sopenharmony_ci	/* Cache the BO id, if not cached already */
6528e5c31af7Sopenharmony_ci	DE_ASSERT(m_sparse_bo == 0 || m_sparse_bo == sparse_bo);
6529e5c31af7Sopenharmony_ci
6530e5c31af7Sopenharmony_ci	m_sparse_bo = sparse_bo;
6531e5c31af7Sopenharmony_ci
6532e5c31af7Sopenharmony_ci	/* Set up the sparse buffer bindings. */
6533e5c31af7Sopenharmony_ci	m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_sparse_bo);
6534e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call(s) failed.");
6535e5c31af7Sopenharmony_ci
6536e5c31af7Sopenharmony_ci	m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
6537e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
6538e5c31af7Sopenharmony_ci
6539e5c31af7Sopenharmony_ci	m_gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_tf_bo);
6540e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
6541e5c31af7Sopenharmony_ci
6542e5c31af7Sopenharmony_ci	return result;
6543e5c31af7Sopenharmony_ci}
6544e5c31af7Sopenharmony_ci
6545e5c31af7Sopenharmony_ci/** Constructor.
6546e5c31af7Sopenharmony_ci *
6547e5c31af7Sopenharmony_ci *  @param context     Rendering context
6548e5c31af7Sopenharmony_ci *  @param name        Test name
6549e5c31af7Sopenharmony_ci *  @param description Test description
6550e5c31af7Sopenharmony_ci */
6551e5c31af7Sopenharmony_ciBufferStorageTest::BufferStorageTest(deqp::Context& context)
6552e5c31af7Sopenharmony_ci	: TestCase(context, "BufferStorageTest", "Tests various interactions between sparse buffers and other API areas")
6553e5c31af7Sopenharmony_ci	, m_sparse_bo(0)
6554e5c31af7Sopenharmony_ci{
6555e5c31af7Sopenharmony_ci	/* Left blank intentionally */
6556e5c31af7Sopenharmony_ci}
6557e5c31af7Sopenharmony_ci
6558e5c31af7Sopenharmony_ci/** Tears down any GL objects set up to run the test. */
6559e5c31af7Sopenharmony_civoid BufferStorageTest::deinit()
6560e5c31af7Sopenharmony_ci{
6561e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
6562e5c31af7Sopenharmony_ci
6563e5c31af7Sopenharmony_ci	/* De-initialize all test the test cases */
6564e5c31af7Sopenharmony_ci	for (TestCasesVectorIterator itTestCase = m_testCases.begin(); itTestCase != m_testCases.end(); ++itTestCase)
6565e5c31af7Sopenharmony_ci	{
6566e5c31af7Sopenharmony_ci		(*itTestCase)->deinitTestCaseGlobal();
6567e5c31af7Sopenharmony_ci
6568e5c31af7Sopenharmony_ci		delete (*itTestCase);
6569e5c31af7Sopenharmony_ci	} /* for (all registered test case objects) */
6570e5c31af7Sopenharmony_ci
6571e5c31af7Sopenharmony_ci	m_testCases.clear();
6572e5c31af7Sopenharmony_ci
6573e5c31af7Sopenharmony_ci	if (m_sparse_bo != 0)
6574e5c31af7Sopenharmony_ci	{
6575e5c31af7Sopenharmony_ci		gl.deleteBuffers(1, &m_sparse_bo);
6576e5c31af7Sopenharmony_ci
6577e5c31af7Sopenharmony_ci		m_sparse_bo = 0;
6578e5c31af7Sopenharmony_ci	}
6579e5c31af7Sopenharmony_ci}
6580e5c31af7Sopenharmony_ci
6581e5c31af7Sopenharmony_ci/** Stub init method */
6582e5c31af7Sopenharmony_civoid BufferStorageTest::init()
6583e5c31af7Sopenharmony_ci{
6584e5c31af7Sopenharmony_ci	/* We cannot initialize the test case objects here as there are cases where there
6585e5c31af7Sopenharmony_ci	 * is no rendering context bound to the thread, when this method is called. */
6586e5c31af7Sopenharmony_ci}
6587e5c31af7Sopenharmony_ci
6588e5c31af7Sopenharmony_ci/** Fills m_testCases with BufferStorageTestCase instances which implement the sub-cases
6589e5c31af7Sopenharmony_ci *  for the second test described in the CTS_ARB_sparse_buffer test specification
6590e5c31af7Sopenharmony_ci **/
6591e5c31af7Sopenharmony_civoid BufferStorageTest::initTestCases()
6592e5c31af7Sopenharmony_ci{
6593e5c31af7Sopenharmony_ci	const glw::Functions& gl		= m_context.getRenderContext().getFunctions();
6594e5c31af7Sopenharmony_ci	glw::GLint			  page_size = 0;
6595e5c31af7Sopenharmony_ci
6596e5c31af7Sopenharmony_ci	/* Retrieve "sparse buffer" GL constant values and entry-point func ptrs */
6597e5c31af7Sopenharmony_ci	gl.getIntegerv(GL_SPARSE_BUFFER_PAGE_SIZE_ARB, &page_size);
6598e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_SPARSE_BUFFER_PAGE_SIZE_ARB pname");
6599e5c31af7Sopenharmony_ci
6600e5c31af7Sopenharmony_ci	/* Initialize all test case objects:
6601e5c31af7Sopenharmony_ci	 *
6602e5c31af7Sopenharmony_ci	 * Test cases a1-a6 */
6603e5c31af7Sopenharmony_ci	m_testCases.push_back(new QuadsBufferStorageTestCase(
6604e5c31af7Sopenharmony_ci		gl, m_testCtx, page_size, QuadsBufferStorageTestCase::IBO_USAGE_NONE, false)); /* use_color_data */
6605e5c31af7Sopenharmony_ci	m_testCases.push_back(new QuadsBufferStorageTestCase(
6606e5c31af7Sopenharmony_ci		gl, m_testCtx, page_size, QuadsBufferStorageTestCase::IBO_USAGE_INDEXED_DRAW_CALL, false)); /* use_color_data */
6607e5c31af7Sopenharmony_ci	m_testCases.push_back(new QuadsBufferStorageTestCase(gl, m_testCtx, page_size,
6608e5c31af7Sopenharmony_ci														 QuadsBufferStorageTestCase::IBO_USAGE_INDEXED_RANGED_DRAW_CALL,
6609e5c31af7Sopenharmony_ci														 false)); /* use_color_data */
6610e5c31af7Sopenharmony_ci	m_testCases.push_back(new QuadsBufferStorageTestCase(
6611e5c31af7Sopenharmony_ci		gl, m_testCtx, page_size, QuadsBufferStorageTestCase::IBO_USAGE_INDEXED_DRAW_CALL, true)); /* use_color_data */
6612e5c31af7Sopenharmony_ci	m_testCases.push_back(new QuadsBufferStorageTestCase(gl, m_testCtx, page_size,
6613e5c31af7Sopenharmony_ci														 QuadsBufferStorageTestCase::IBO_USAGE_INDEXED_RANGED_DRAW_CALL,
6614e5c31af7Sopenharmony_ci														 true)); /* use_color_data */
6615e5c31af7Sopenharmony_ci
6616e5c31af7Sopenharmony_ci	/* Test case b1 */
6617e5c31af7Sopenharmony_ci	m_testCases.push_back(
6618e5c31af7Sopenharmony_ci		new TransformFeedbackBufferStorageTestCase(gl, m_testCtx, page_size, true)); /* all_tf_pages_committed */
6619e5c31af7Sopenharmony_ci
6620e5c31af7Sopenharmony_ci	/* Test case b2 */
6621e5c31af7Sopenharmony_ci	m_testCases.push_back(
6622e5c31af7Sopenharmony_ci		new TransformFeedbackBufferStorageTestCase(gl, m_testCtx, page_size, false)); /* all_tf_pages_committed */
6623e5c31af7Sopenharmony_ci
6624e5c31af7Sopenharmony_ci	/* Test case c */
6625e5c31af7Sopenharmony_ci	m_testCases.push_back(new ClearOpsBufferStorageTestCase(gl, m_testCtx, page_size));
6626e5c31af7Sopenharmony_ci
6627e5c31af7Sopenharmony_ci	/* Test case d */
6628e5c31af7Sopenharmony_ci	m_testCases.push_back(new InvalidateBufferStorageTestCase(gl, m_testCtx, page_size));
6629e5c31af7Sopenharmony_ci
6630e5c31af7Sopenharmony_ci	/* Test case e */
6631e5c31af7Sopenharmony_ci	m_testCases.push_back(
6632e5c31af7Sopenharmony_ci		new AtomicCounterBufferStorageTestCase(gl, m_testCtx, page_size, false)); /* all_pages_committed */
6633e5c31af7Sopenharmony_ci	m_testCases.push_back(
6634e5c31af7Sopenharmony_ci		new AtomicCounterBufferStorageTestCase(gl, m_testCtx, page_size, true)); /* all_pages_committed */
6635e5c31af7Sopenharmony_ci
6636e5c31af7Sopenharmony_ci	/* Test case f */
6637e5c31af7Sopenharmony_ci	m_testCases.push_back(new BufferTextureStorageTestCase(gl, m_context, m_testCtx, page_size));
6638e5c31af7Sopenharmony_ci
6639e5c31af7Sopenharmony_ci	/* Test case g */
6640e5c31af7Sopenharmony_ci	m_testCases.push_back(new CopyOpsBufferStorageTestCase(gl, m_testCtx, page_size));
6641e5c31af7Sopenharmony_ci
6642e5c31af7Sopenharmony_ci	/* Test case h */
6643e5c31af7Sopenharmony_ci	m_testCases.push_back(new IndirectDispatchBufferStorageTestCase(gl, m_testCtx, page_size));
6644e5c31af7Sopenharmony_ci
6645e5c31af7Sopenharmony_ci	/* Test case i */
6646e5c31af7Sopenharmony_ci	m_testCases.push_back(new SSBOStorageTestCase(gl, m_testCtx, page_size));
6647e5c31af7Sopenharmony_ci
6648e5c31af7Sopenharmony_ci	/* Test case j */
6649e5c31af7Sopenharmony_ci	m_testCases.push_back(new UniformBufferStorageTestCase(gl, m_testCtx, page_size));
6650e5c31af7Sopenharmony_ci
6651e5c31af7Sopenharmony_ci	/* Test case k */
6652e5c31af7Sopenharmony_ci	m_testCases.push_back(new PixelPackBufferStorageTestCase(gl, m_testCtx, page_size));
6653e5c31af7Sopenharmony_ci
6654e5c31af7Sopenharmony_ci	/* Test case l */
6655e5c31af7Sopenharmony_ci	m_testCases.push_back(new PixelUnpackBufferStorageTestCase(gl, m_testCtx, page_size));
6656e5c31af7Sopenharmony_ci
6657e5c31af7Sopenharmony_ci	/* Test case m */
6658e5c31af7Sopenharmony_ci	m_testCases.push_back(new QueryBufferStorageTestCase(gl, m_testCtx, page_size));
6659e5c31af7Sopenharmony_ci
6660e5c31af7Sopenharmony_ci	/* Initialize all test cases */
6661e5c31af7Sopenharmony_ci	for (TestCasesVectorIterator itTestCase = m_testCases.begin(); itTestCase != m_testCases.end(); ++itTestCase)
6662e5c31af7Sopenharmony_ci	{
6663e5c31af7Sopenharmony_ci		(*itTestCase)->initTestCaseGlobal();
6664e5c31af7Sopenharmony_ci	}
6665e5c31af7Sopenharmony_ci}
6666e5c31af7Sopenharmony_ci
6667e5c31af7Sopenharmony_ci/** Executes test iteration.
6668e5c31af7Sopenharmony_ci *
6669e5c31af7Sopenharmony_ci *  @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
6670e5c31af7Sopenharmony_ci */
6671e5c31af7Sopenharmony_citcu::TestNode::IterateResult BufferStorageTest::iterate()
6672e5c31af7Sopenharmony_ci{
6673e5c31af7Sopenharmony_ci	const glw::Functions& gl	 = m_context.getRenderContext().getFunctions();
6674e5c31af7Sopenharmony_ci	bool				  result = true;
6675e5c31af7Sopenharmony_ci
6676e5c31af7Sopenharmony_ci	/* Only execute if the implementation supports the GL_ARB_sparse_buffer extension */
6677e5c31af7Sopenharmony_ci	if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_sparse_buffer"))
6678e5c31af7Sopenharmony_ci	{
6679e5c31af7Sopenharmony_ci		throw tcu::NotSupportedError("GL_ARB_sparse_buffer is not supported");
6680e5c31af7Sopenharmony_ci	}
6681e5c31af7Sopenharmony_ci
6682e5c31af7Sopenharmony_ci	/* The buffer storage test cases require OpenGL 4.3 feature-set. */
6683e5c31af7Sopenharmony_ci	if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 3)))
6684e5c31af7Sopenharmony_ci	{
6685e5c31af7Sopenharmony_ci		throw tcu::NotSupportedError("GL_ARB_sparse_buffer conformance tests require OpenGL 4.3 core feature-set");
6686e5c31af7Sopenharmony_ci	}
6687e5c31af7Sopenharmony_ci
6688e5c31af7Sopenharmony_ci	/* Register & initialize the test case objects */
6689e5c31af7Sopenharmony_ci	initTestCases();
6690e5c31af7Sopenharmony_ci
6691e5c31af7Sopenharmony_ci	/* Iterate over all sparse BO flag combinations. We need to consider a total of 4 flags:
6692e5c31af7Sopenharmony_ci	 *
6693e5c31af7Sopenharmony_ci	 * - GL_CLIENT_STORAGE_BIT  (bit 0)
6694e5c31af7Sopenharmony_ci	 * - GL_DYNAMIC_STORAGE_BIT (bit 1)
6695e5c31af7Sopenharmony_ci	 * - GL_MAP_COHERENT_BIT    (bit 2)
6696e5c31af7Sopenharmony_ci	 * - GL_MAP_PERSISTENT_BIT  (bit 3)
6697e5c31af7Sopenharmony_ci	 *
6698e5c31af7Sopenharmony_ci	 *  GL_MAP_READ_BIT and GL_MAP_WRITE_BIT are excluded, since they are incompatible
6699e5c31af7Sopenharmony_ci	 *  with sparse buffers by definition.
6700e5c31af7Sopenharmony_ci	 *
6701e5c31af7Sopenharmony_ci	 *  GL_SPARSE_STORAGE_BIT_ARB is assumed to be always defined. Some of the combinations are invalid.
6702e5c31af7Sopenharmony_ci	 *  Such loop iterations will be skipped.
6703e5c31af7Sopenharmony_ci	 * */
6704e5c31af7Sopenharmony_ci
6705e5c31af7Sopenharmony_ci	for (unsigned int n_flag_combination = 0; n_flag_combination < (1 << 4); ++n_flag_combination)
6706e5c31af7Sopenharmony_ci	{
6707e5c31af7Sopenharmony_ci		const glw::GLint flags = ((n_flag_combination & (1 << 0)) ? GL_CLIENT_STORAGE_BIT : 0) |
6708e5c31af7Sopenharmony_ci								 ((n_flag_combination & (1 << 1)) ? GL_DYNAMIC_STORAGE_BIT : 0) |
6709e5c31af7Sopenharmony_ci								 ((n_flag_combination & (1 << 2)) ? GL_MAP_COHERENT_BIT : 0) |
6710e5c31af7Sopenharmony_ci								 ((n_flag_combination & (1 << 3)) ? GL_MAP_PERSISTENT_BIT : 0) |
6711e5c31af7Sopenharmony_ci								 GL_SPARSE_STORAGE_BIT_ARB;
6712e5c31af7Sopenharmony_ci
6713e5c31af7Sopenharmony_ci		if ((flags & GL_MAP_PERSISTENT_BIT) != 0)
6714e5c31af7Sopenharmony_ci		{
6715e5c31af7Sopenharmony_ci			if ((flags & GL_MAP_READ_BIT) == 0 && (flags & GL_MAP_WRITE_BIT) == 0)
6716e5c31af7Sopenharmony_ci			{
6717e5c31af7Sopenharmony_ci				continue;
6718e5c31af7Sopenharmony_ci			}
6719e5c31af7Sopenharmony_ci		}
6720e5c31af7Sopenharmony_ci
6721e5c31af7Sopenharmony_ci		if (((flags & GL_MAP_COHERENT_BIT) != 0) && ((flags & GL_MAP_PERSISTENT_BIT) == 0))
6722e5c31af7Sopenharmony_ci		{
6723e5c31af7Sopenharmony_ci			continue;
6724e5c31af7Sopenharmony_ci		}
6725e5c31af7Sopenharmony_ci
6726e5c31af7Sopenharmony_ci		/* Set up the sparse BO */
6727e5c31af7Sopenharmony_ci		gl.genBuffers(1, &m_sparse_bo);
6728e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed.");
6729e5c31af7Sopenharmony_ci
6730e5c31af7Sopenharmony_ci		gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
6731e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed.");
6732e5c31af7Sopenharmony_ci
6733e5c31af7Sopenharmony_ci		gl.bufferStorage(GL_ARRAY_BUFFER, 1024768 * 1024, /* as per test spec */
6734e5c31af7Sopenharmony_ci						 DE_NULL,						  /* data */
6735e5c31af7Sopenharmony_ci						 flags);
6736e5c31af7Sopenharmony_ci
6737e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferStorage() call failed.");
6738e5c31af7Sopenharmony_ci
6739e5c31af7Sopenharmony_ci		for (TestCasesVectorIterator itTestCase = m_testCases.begin(); itTestCase != m_testCases.end(); ++itTestCase)
6740e5c31af7Sopenharmony_ci		{
6741e5c31af7Sopenharmony_ci			gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
6742e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed.");
6743e5c31af7Sopenharmony_ci
6744e5c31af7Sopenharmony_ci			if (!(*itTestCase)->initTestCaseIteration(m_sparse_bo))
6745e5c31af7Sopenharmony_ci			{
6746e5c31af7Sopenharmony_ci				m_testCtx.getLog() << tcu::TestLog::Message << "Test case [" << (*itTestCase)->getName()
6747e5c31af7Sopenharmony_ci								   << "] "
6748e5c31af7Sopenharmony_ci									  "has failed to initialize."
6749e5c31af7Sopenharmony_ci								   << tcu::TestLog::EndMessage;
6750e5c31af7Sopenharmony_ci
6751e5c31af7Sopenharmony_ci				result = false;
6752e5c31af7Sopenharmony_ci				goto end;
6753e5c31af7Sopenharmony_ci			}
6754e5c31af7Sopenharmony_ci
6755e5c31af7Sopenharmony_ci			if (!(*itTestCase)->execute(flags))
6756e5c31af7Sopenharmony_ci			{
6757e5c31af7Sopenharmony_ci				m_testCtx.getLog() << tcu::TestLog::Message << "Test case [" << (*itTestCase)->getName()
6758e5c31af7Sopenharmony_ci								   << "] "
6759e5c31af7Sopenharmony_ci									  "has failed to execute correctly."
6760e5c31af7Sopenharmony_ci								   << tcu::TestLog::EndMessage;
6761e5c31af7Sopenharmony_ci
6762e5c31af7Sopenharmony_ci				result = false;
6763e5c31af7Sopenharmony_ci			} /* if (!testCaseResult) */
6764e5c31af7Sopenharmony_ci
6765e5c31af7Sopenharmony_ci			(*itTestCase)->deinitTestCaseIteration();
6766e5c31af7Sopenharmony_ci		} /* for (all added test cases) */
6767e5c31af7Sopenharmony_ci
6768e5c31af7Sopenharmony_ci		/* Release the sparse BO */
6769e5c31af7Sopenharmony_ci		gl.deleteBuffers(1, &m_sparse_bo);
6770e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteBuffers() call failed.");
6771e5c31af7Sopenharmony_ci
6772e5c31af7Sopenharmony_ci		m_sparse_bo = 0;
6773e5c31af7Sopenharmony_ci	}
6774e5c31af7Sopenharmony_ci
6775e5c31af7Sopenharmony_ciend:
6776e5c31af7Sopenharmony_ci	m_testCtx.setTestResult(result ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, result ? "Pass" : "Fail");
6777e5c31af7Sopenharmony_ci
6778e5c31af7Sopenharmony_ci	return STOP;
6779e5c31af7Sopenharmony_ci}
6780e5c31af7Sopenharmony_ci
6781e5c31af7Sopenharmony_ci/** Constructor.
6782e5c31af7Sopenharmony_ci *
6783e5c31af7Sopenharmony_ci *  @param context Rendering context.
6784e5c31af7Sopenharmony_ci */
6785e5c31af7Sopenharmony_ciSparseBufferTests::SparseBufferTests(deqp::Context& context)
6786e5c31af7Sopenharmony_ci	: TestCaseGroup(context, "sparse_buffer_tests", "Verify conformance of CTS_ARB_sparse_buffer implementation")
6787e5c31af7Sopenharmony_ci{
6788e5c31af7Sopenharmony_ci}
6789e5c31af7Sopenharmony_ci
6790e5c31af7Sopenharmony_ci/** Initializes the test group contents. */
6791e5c31af7Sopenharmony_civoid SparseBufferTests::init()
6792e5c31af7Sopenharmony_ci{
6793e5c31af7Sopenharmony_ci	addChild(new BufferStorageTest(m_context));
6794e5c31af7Sopenharmony_ci	addChild(new NegativeTests(m_context));
6795e5c31af7Sopenharmony_ci	addChild(new PageSizeGetterTest(m_context));
6796e5c31af7Sopenharmony_ci}
6797e5c31af7Sopenharmony_ci
6798e5c31af7Sopenharmony_ci} /* gl4cts namespace */
6799