1e5c31af7Sopenharmony_ci/*-------------------------------------------------------------------------
2e5c31af7Sopenharmony_ci * drawElements Quality Program OpenGL (ES) Module
3e5c31af7Sopenharmony_ci * -----------------------------------------------
4e5c31af7Sopenharmony_ci *
5e5c31af7Sopenharmony_ci * Copyright 2014 The Android Open Source Project
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 Fragment operation test utilities.
22e5c31af7Sopenharmony_ci *//*--------------------------------------------------------------------*/
23e5c31af7Sopenharmony_ci
24e5c31af7Sopenharmony_ci#include "glsFragmentOpUtil.hpp"
25e5c31af7Sopenharmony_ci#include "gluRenderContext.hpp"
26e5c31af7Sopenharmony_ci#include "gluShaderProgram.hpp"
27e5c31af7Sopenharmony_ci#include "gluDrawUtil.hpp"
28e5c31af7Sopenharmony_ci#include "glwFunctions.hpp"
29e5c31af7Sopenharmony_ci#include "glwEnums.hpp"
30e5c31af7Sopenharmony_ci
31e5c31af7Sopenharmony_cinamespace deqp
32e5c31af7Sopenharmony_ci{
33e5c31af7Sopenharmony_cinamespace gls
34e5c31af7Sopenharmony_ci{
35e5c31af7Sopenharmony_cinamespace FragmentOpUtil
36e5c31af7Sopenharmony_ci{
37e5c31af7Sopenharmony_ci
38e5c31af7Sopenharmony_citemplate<typename T>
39e5c31af7Sopenharmony_ciinline T triQuadInterpolate (const T values[4], float xFactor, float yFactor)
40e5c31af7Sopenharmony_ci{
41e5c31af7Sopenharmony_ci	if (xFactor + yFactor < 1.0f)
42e5c31af7Sopenharmony_ci		return values[0] + (values[2]-values[0])*xFactor		+ (values[1]-values[0])*yFactor;
43e5c31af7Sopenharmony_ci	else
44e5c31af7Sopenharmony_ci		return values[3] + (values[1]-values[3])*(1.0f-xFactor)	+ (values[2]-values[3])*(1.0f-yFactor);
45e5c31af7Sopenharmony_ci}
46e5c31af7Sopenharmony_ci
47e5c31af7Sopenharmony_ci// GLSL ES 1.0 shaders
48e5c31af7Sopenharmony_cistatic const char* s_glsl1VertSrc =
49e5c31af7Sopenharmony_ci	"attribute highp vec4 a_position;\n"
50e5c31af7Sopenharmony_ci	"attribute mediump vec4 a_color;\n"
51e5c31af7Sopenharmony_ci	"varying mediump vec4 v_color;\n"
52e5c31af7Sopenharmony_ci	"void main()\n"
53e5c31af7Sopenharmony_ci	"{\n"
54e5c31af7Sopenharmony_ci	"	gl_Position = a_position;\n"
55e5c31af7Sopenharmony_ci	"	v_color = a_color;\n"
56e5c31af7Sopenharmony_ci	"}\n";
57e5c31af7Sopenharmony_cistatic const char* s_glsl1FragSrc =
58e5c31af7Sopenharmony_ci	"varying mediump vec4 v_color;\n"
59e5c31af7Sopenharmony_ci	"void main()\n"
60e5c31af7Sopenharmony_ci	"{\n"
61e5c31af7Sopenharmony_ci	"	gl_FragColor = v_color;\n"
62e5c31af7Sopenharmony_ci	"}\n";
63e5c31af7Sopenharmony_ci
64e5c31af7Sopenharmony_ci// GLSL ES 3.0 shaders
65e5c31af7Sopenharmony_cistatic const char* s_glsl3VertSrc =
66e5c31af7Sopenharmony_ci	"#version 300 es\n"
67e5c31af7Sopenharmony_ci	"in highp vec4 a_position;\n"
68e5c31af7Sopenharmony_ci	"in mediump vec4 a_color;\n"
69e5c31af7Sopenharmony_ci	"out mediump vec4 v_color;\n"
70e5c31af7Sopenharmony_ci	"void main()\n"
71e5c31af7Sopenharmony_ci	"{\n"
72e5c31af7Sopenharmony_ci	"	gl_Position = a_position;\n"
73e5c31af7Sopenharmony_ci	"	v_color = a_color;\n"
74e5c31af7Sopenharmony_ci	"}\n";
75e5c31af7Sopenharmony_cistatic const char* s_glsl3FragSrc =
76e5c31af7Sopenharmony_ci	"#version 300 es\n"
77e5c31af7Sopenharmony_ci	"in mediump vec4 v_color;\n"
78e5c31af7Sopenharmony_ci	"layout(location = 0) out mediump vec4 o_color;\n"
79e5c31af7Sopenharmony_ci	"void main()\n"
80e5c31af7Sopenharmony_ci	"{\n"
81e5c31af7Sopenharmony_ci	"	o_color = v_color;\n"
82e5c31af7Sopenharmony_ci	"}\n";
83e5c31af7Sopenharmony_ci
84e5c31af7Sopenharmony_ci// GLSL 3.3 shaders
85e5c31af7Sopenharmony_cistatic const char* s_glsl33VertSrc =
86e5c31af7Sopenharmony_ci	"#version 330 core\n"
87e5c31af7Sopenharmony_ci	"in vec4 a_position;\n"
88e5c31af7Sopenharmony_ci	"in vec4 a_color;\n"
89e5c31af7Sopenharmony_ci	"in vec4 a_color1;\n"
90e5c31af7Sopenharmony_ci	"out vec4 v_color;\n"
91e5c31af7Sopenharmony_ci	"out vec4 v_color1;\n"
92e5c31af7Sopenharmony_ci	"void main()\n"
93e5c31af7Sopenharmony_ci	"{\n"
94e5c31af7Sopenharmony_ci	"	gl_Position	= a_position;\n"
95e5c31af7Sopenharmony_ci	"	v_color		= a_color;\n"
96e5c31af7Sopenharmony_ci	"	v_color1	= a_color1;\n"
97e5c31af7Sopenharmony_ci	"}\n";
98e5c31af7Sopenharmony_cistatic const char* s_glsl33FragSrc =
99e5c31af7Sopenharmony_ci	"#version 330 core\n"
100e5c31af7Sopenharmony_ci	"in vec4 v_color;\n"
101e5c31af7Sopenharmony_ci	"in vec4 v_color1;\n"
102e5c31af7Sopenharmony_ci	"layout(location = 0, index = 0) out vec4 o_color;\n"
103e5c31af7Sopenharmony_ci	"layout(location = 0, index = 1) out vec4 o_color1;\n"
104e5c31af7Sopenharmony_ci	"void main()\n"
105e5c31af7Sopenharmony_ci	"{\n"
106e5c31af7Sopenharmony_ci	"	o_color  = v_color;\n"
107e5c31af7Sopenharmony_ci	"	o_color1 = v_color1;\n"
108e5c31af7Sopenharmony_ci	"}\n";
109e5c31af7Sopenharmony_ci
110e5c31af7Sopenharmony_cistatic const char* getVertSrc (glu::GLSLVersion glslVersion)
111e5c31af7Sopenharmony_ci{
112e5c31af7Sopenharmony_ci	if (glslVersion == glu::GLSL_VERSION_100_ES)
113e5c31af7Sopenharmony_ci		return s_glsl1VertSrc;
114e5c31af7Sopenharmony_ci	else if (glslVersion == glu::GLSL_VERSION_300_ES)
115e5c31af7Sopenharmony_ci		return s_glsl3VertSrc;
116e5c31af7Sopenharmony_ci	else if (glslVersion == glu::GLSL_VERSION_330)
117e5c31af7Sopenharmony_ci		return s_glsl33VertSrc;
118e5c31af7Sopenharmony_ci
119e5c31af7Sopenharmony_ci	DE_ASSERT(DE_FALSE);
120e5c31af7Sopenharmony_ci	return 0;
121e5c31af7Sopenharmony_ci}
122e5c31af7Sopenharmony_ci
123e5c31af7Sopenharmony_cistatic const char* getFragSrc (glu::GLSLVersion glslVersion)
124e5c31af7Sopenharmony_ci{
125e5c31af7Sopenharmony_ci	if (glslVersion == glu::GLSL_VERSION_100_ES)
126e5c31af7Sopenharmony_ci		return s_glsl1FragSrc;
127e5c31af7Sopenharmony_ci	else if (glslVersion == glu::GLSL_VERSION_300_ES)
128e5c31af7Sopenharmony_ci		return s_glsl3FragSrc;
129e5c31af7Sopenharmony_ci	else if (glslVersion == glu::GLSL_VERSION_330)
130e5c31af7Sopenharmony_ci		return s_glsl33FragSrc;
131e5c31af7Sopenharmony_ci
132e5c31af7Sopenharmony_ci	DE_ASSERT(DE_FALSE);
133e5c31af7Sopenharmony_ci	return 0;
134e5c31af7Sopenharmony_ci}
135e5c31af7Sopenharmony_ci
136e5c31af7Sopenharmony_ciQuadRenderer::QuadRenderer (const glu::RenderContext& context, glu::GLSLVersion glslVersion)
137e5c31af7Sopenharmony_ci	: m_context			(context)
138e5c31af7Sopenharmony_ci	, m_program			(DE_NULL)
139e5c31af7Sopenharmony_ci	, m_positionLoc		(0)
140e5c31af7Sopenharmony_ci	, m_colorLoc		(-1)
141e5c31af7Sopenharmony_ci	, m_color1Loc		(-1)
142e5c31af7Sopenharmony_ci	, m_blendFuncExt	(!glu::glslVersionIsES(glslVersion) && (glslVersion >= glu::GLSL_VERSION_330))
143e5c31af7Sopenharmony_ci{
144e5c31af7Sopenharmony_ci	DE_ASSERT(glslVersion == glu::GLSL_VERSION_100_ES ||
145e5c31af7Sopenharmony_ci			  glslVersion == glu::GLSL_VERSION_300_ES ||
146e5c31af7Sopenharmony_ci			  glslVersion == glu::GLSL_VERSION_330);
147e5c31af7Sopenharmony_ci
148e5c31af7Sopenharmony_ci	const glw::Functions&	gl		= context.getFunctions();
149e5c31af7Sopenharmony_ci	const char*				vertSrc	= getVertSrc(glslVersion);
150e5c31af7Sopenharmony_ci	const char*				fragSrc	= getFragSrc(glslVersion);
151e5c31af7Sopenharmony_ci
152e5c31af7Sopenharmony_ci	m_program = new glu::ShaderProgram(m_context, glu::makeVtxFragSources(vertSrc, fragSrc));
153e5c31af7Sopenharmony_ci	if (!m_program->isOk())
154e5c31af7Sopenharmony_ci	{
155e5c31af7Sopenharmony_ci		delete m_program;
156e5c31af7Sopenharmony_ci		throw tcu::TestError("Failed to compile program", DE_NULL, __FILE__, __LINE__);
157e5c31af7Sopenharmony_ci	}
158e5c31af7Sopenharmony_ci
159e5c31af7Sopenharmony_ci	m_positionLoc	= gl.getAttribLocation(m_program->getProgram(), "a_position");
160e5c31af7Sopenharmony_ci	m_colorLoc		= gl.getAttribLocation(m_program->getProgram(), "a_color");
161e5c31af7Sopenharmony_ci
162e5c31af7Sopenharmony_ci	if (m_blendFuncExt)
163e5c31af7Sopenharmony_ci		m_color1Loc = gl.getAttribLocation(m_program->getProgram(), "a_color1");
164e5c31af7Sopenharmony_ci
165e5c31af7Sopenharmony_ci	if (m_positionLoc < 0 || m_colorLoc < 0 || (m_blendFuncExt && m_color1Loc < 0))
166e5c31af7Sopenharmony_ci	{
167e5c31af7Sopenharmony_ci		delete m_program;
168e5c31af7Sopenharmony_ci		throw tcu::TestError("Invalid attribute locations", DE_NULL, __FILE__, __LINE__);
169e5c31af7Sopenharmony_ci	}
170e5c31af7Sopenharmony_ci}
171e5c31af7Sopenharmony_ci
172e5c31af7Sopenharmony_ciQuadRenderer::~QuadRenderer (void)
173e5c31af7Sopenharmony_ci{
174e5c31af7Sopenharmony_ci	delete m_program;
175e5c31af7Sopenharmony_ci}
176e5c31af7Sopenharmony_ci
177e5c31af7Sopenharmony_civoid QuadRenderer::render (const Quad& quad) const
178e5c31af7Sopenharmony_ci{
179e5c31af7Sopenharmony_ci	const float position[] =
180e5c31af7Sopenharmony_ci	{
181e5c31af7Sopenharmony_ci		quad.posA.x(), quad.posA.y(), quad.depth[0], 1.0f,
182e5c31af7Sopenharmony_ci		quad.posA.x(), quad.posB.y(), quad.depth[1], 1.0f,
183e5c31af7Sopenharmony_ci		quad.posB.x(), quad.posA.y(), quad.depth[2], 1.0f,
184e5c31af7Sopenharmony_ci		quad.posB.x(), quad.posB.y(), quad.depth[3], 1.0f
185e5c31af7Sopenharmony_ci	};
186e5c31af7Sopenharmony_ci	const deUint8 indices[] = { 0, 2, 1, 1, 2, 3 };
187e5c31af7Sopenharmony_ci
188e5c31af7Sopenharmony_ci	DE_STATIC_ASSERT(sizeof(tcu::Vec4) == sizeof(float)*4);
189e5c31af7Sopenharmony_ci	DE_STATIC_ASSERT(sizeof(quad.color) == sizeof(float)*4*4);
190e5c31af7Sopenharmony_ci	DE_STATIC_ASSERT(sizeof(quad.color1) == sizeof(float)*4*4);
191e5c31af7Sopenharmony_ci
192e5c31af7Sopenharmony_ci	std::vector<glu::VertexArrayBinding> vertexArrays;
193e5c31af7Sopenharmony_ci
194e5c31af7Sopenharmony_ci	vertexArrays.push_back(glu::va::Float(m_positionLoc,	4, 4, 0, &position[0]));
195e5c31af7Sopenharmony_ci	vertexArrays.push_back(glu::va::Float(m_colorLoc,		4, 4, 0, (const float*)&quad.color[0]));
196e5c31af7Sopenharmony_ci
197e5c31af7Sopenharmony_ci	if (m_blendFuncExt)
198e5c31af7Sopenharmony_ci		vertexArrays.push_back(glu::va::Float(m_color1Loc,	4, 4, 0, (const float*)&quad.color1[0]));
199e5c31af7Sopenharmony_ci
200e5c31af7Sopenharmony_ci	m_context.getFunctions().useProgram(m_program->getProgram());
201e5c31af7Sopenharmony_ci	glu::draw(m_context, m_program->getProgram(),
202e5c31af7Sopenharmony_ci			  (int)vertexArrays.size(), &vertexArrays[0],
203e5c31af7Sopenharmony_ci			  glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0]));
204e5c31af7Sopenharmony_ci}
205e5c31af7Sopenharmony_ci
206e5c31af7Sopenharmony_ciReferenceQuadRenderer::ReferenceQuadRenderer (void)
207e5c31af7Sopenharmony_ci	: m_fragmentBufferSize(0)
208e5c31af7Sopenharmony_ci{
209e5c31af7Sopenharmony_ci	for (int i = 0; i < DE_LENGTH_OF_ARRAY(m_fragmentDepths); i++)
210e5c31af7Sopenharmony_ci		m_fragmentDepths[i] = 0.0f;
211e5c31af7Sopenharmony_ci}
212e5c31af7Sopenharmony_ci
213e5c31af7Sopenharmony_civoid ReferenceQuadRenderer::flushFragmentBuffer (const rr::MultisamplePixelBufferAccess&	colorBuffer,
214e5c31af7Sopenharmony_ci												 const rr::MultisamplePixelBufferAccess&	depthBuffer,
215e5c31af7Sopenharmony_ci												 const rr::MultisamplePixelBufferAccess&	stencilBuffer,
216e5c31af7Sopenharmony_ci												 rr::FaceType								faceType,
217e5c31af7Sopenharmony_ci												 const rr::FragmentOperationState&			state)
218e5c31af7Sopenharmony_ci{
219e5c31af7Sopenharmony_ci	m_fragmentProcessor.render(colorBuffer, depthBuffer, stencilBuffer, &m_fragmentBuffer[0], m_fragmentBufferSize, faceType, state);
220e5c31af7Sopenharmony_ci	m_fragmentBufferSize = 0;
221e5c31af7Sopenharmony_ci}
222e5c31af7Sopenharmony_ci
223e5c31af7Sopenharmony_civoid ReferenceQuadRenderer::render (const tcu::PixelBufferAccess&			colorBuffer,
224e5c31af7Sopenharmony_ci									const tcu::PixelBufferAccess&			depthBuffer,
225e5c31af7Sopenharmony_ci									const tcu::PixelBufferAccess&			stencilBuffer,
226e5c31af7Sopenharmony_ci									const IntegerQuad&						quad,
227e5c31af7Sopenharmony_ci									const rr::FragmentOperationState&		state)
228e5c31af7Sopenharmony_ci{
229e5c31af7Sopenharmony_ci	bool			flipX			= quad.posA.x() > quad.posB.x();
230e5c31af7Sopenharmony_ci	bool			flipY			= quad.posA.y() > quad.posB.y();
231e5c31af7Sopenharmony_ci	rr::FaceType	faceType		= flipX == flipY ? rr::FACETYPE_FRONT : rr::FACETYPE_BACK;
232e5c31af7Sopenharmony_ci	int				xFirst			= flipX ? quad.posB.x() : quad.posA.x();
233e5c31af7Sopenharmony_ci	int				xLast			= flipX ? quad.posA.x() : quad.posB.x();
234e5c31af7Sopenharmony_ci	int				yFirst			= flipY ? quad.posB.y() : quad.posA.y();
235e5c31af7Sopenharmony_ci	int				yLast			= flipY ? quad.posA.y() : quad.posB.y();
236e5c31af7Sopenharmony_ci	float			width			= (float)(xLast - xFirst + 1);
237e5c31af7Sopenharmony_ci	float			height			= (float)(yLast - yFirst + 1);
238e5c31af7Sopenharmony_ci
239e5c31af7Sopenharmony_ci	for (int y = yFirst; y <= yLast; y++)
240e5c31af7Sopenharmony_ci	{
241e5c31af7Sopenharmony_ci		// Interpolation factor for y.
242e5c31af7Sopenharmony_ci		float yRatio = (0.5f + (float)(y - yFirst)) / height;
243e5c31af7Sopenharmony_ci		if (flipY)
244e5c31af7Sopenharmony_ci			yRatio = 1.0f - yRatio;
245e5c31af7Sopenharmony_ci
246e5c31af7Sopenharmony_ci		for (int x = xFirst; x <= xLast; x++)
247e5c31af7Sopenharmony_ci		{
248e5c31af7Sopenharmony_ci			// Interpolation factor for x.
249e5c31af7Sopenharmony_ci			float xRatio = (0.5f + (float)(x - xFirst)) / width;
250e5c31af7Sopenharmony_ci			if (flipX)
251e5c31af7Sopenharmony_ci				xRatio = 1.0f - xRatio;
252e5c31af7Sopenharmony_ci
253e5c31af7Sopenharmony_ci			tcu::Vec4	color	= triQuadInterpolate(quad.color, xRatio, yRatio);
254e5c31af7Sopenharmony_ci			tcu::Vec4	color1	= triQuadInterpolate(quad.color1, xRatio, yRatio);
255e5c31af7Sopenharmony_ci			float		depth	= triQuadInterpolate(quad.depth, xRatio, yRatio);
256e5c31af7Sopenharmony_ci
257e5c31af7Sopenharmony_ci			// Interpolated color and depth.
258e5c31af7Sopenharmony_ci
259e5c31af7Sopenharmony_ci			DE_STATIC_ASSERT(MAX_FRAGMENT_BUFFER_SIZE == DE_LENGTH_OF_ARRAY(m_fragmentBuffer));
260e5c31af7Sopenharmony_ci
261e5c31af7Sopenharmony_ci			if (m_fragmentBufferSize >= MAX_FRAGMENT_BUFFER_SIZE)
262e5c31af7Sopenharmony_ci				flushFragmentBuffer(rr::MultisamplePixelBufferAccess::fromMultisampleAccess(colorBuffer),
263e5c31af7Sopenharmony_ci									rr::MultisamplePixelBufferAccess::fromMultisampleAccess(depthBuffer),
264e5c31af7Sopenharmony_ci									rr::MultisamplePixelBufferAccess::fromMultisampleAccess(stencilBuffer), faceType, state);
265e5c31af7Sopenharmony_ci
266e5c31af7Sopenharmony_ci			m_fragmentDepths[m_fragmentBufferSize] = depth;
267e5c31af7Sopenharmony_ci			m_fragmentBuffer[m_fragmentBufferSize] = rr::Fragment(tcu::IVec2(x, y), rr::GenericVec4(color), rr::GenericVec4(color1), 1u /* coverage mask */, &m_fragmentDepths[m_fragmentBufferSize]);
268e5c31af7Sopenharmony_ci			m_fragmentBufferSize++;
269e5c31af7Sopenharmony_ci		}
270e5c31af7Sopenharmony_ci	}
271e5c31af7Sopenharmony_ci
272e5c31af7Sopenharmony_ci	flushFragmentBuffer(rr::MultisamplePixelBufferAccess::fromMultisampleAccess(colorBuffer),
273e5c31af7Sopenharmony_ci						rr::MultisamplePixelBufferAccess::fromMultisampleAccess(depthBuffer),
274e5c31af7Sopenharmony_ci						rr::MultisamplePixelBufferAccess::fromMultisampleAccess(stencilBuffer), faceType, state);
275e5c31af7Sopenharmony_ci}
276e5c31af7Sopenharmony_ci
277e5c31af7Sopenharmony_citcu::PixelBufferAccess getMultisampleAccess(const tcu::PixelBufferAccess& original)
278e5c31af7Sopenharmony_ci{
279e5c31af7Sopenharmony_ci	return tcu::PixelBufferAccess(original.getFormat(),
280e5c31af7Sopenharmony_ci								  1,
281e5c31af7Sopenharmony_ci								  original.getWidth(),
282e5c31af7Sopenharmony_ci								  original.getHeight(),
283e5c31af7Sopenharmony_ci								  original.getFormat().getPixelSize(),
284e5c31af7Sopenharmony_ci								  original.getRowPitch(),
285e5c31af7Sopenharmony_ci								  original.getDataPtr());
286e5c31af7Sopenharmony_ci}
287e5c31af7Sopenharmony_ci
288e5c31af7Sopenharmony_citcu::ConstPixelBufferAccess getMultisampleAccess(const tcu::ConstPixelBufferAccess& original)
289e5c31af7Sopenharmony_ci{
290e5c31af7Sopenharmony_ci	return tcu::ConstPixelBufferAccess(original.getFormat(),
291e5c31af7Sopenharmony_ci									   1,
292e5c31af7Sopenharmony_ci									   original.getWidth(),
293e5c31af7Sopenharmony_ci									   original.getHeight(),
294e5c31af7Sopenharmony_ci									   original.getFormat().getPixelSize(),
295e5c31af7Sopenharmony_ci									   original.getRowPitch(),
296e5c31af7Sopenharmony_ci									   original.getDataPtr());
297e5c31af7Sopenharmony_ci}
298e5c31af7Sopenharmony_ci
299e5c31af7Sopenharmony_ci} // FragmentOpUtil
300e5c31af7Sopenharmony_ci} // gls
301e5c31af7Sopenharmony_ci} // deqp
302