1e5c31af7Sopenharmony_ci/*-------------------------------------------------------------------------
2e5c31af7Sopenharmony_ci * drawElements Quality Program OpenGL ES Utilities
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 Wrapper for GL program object.
22e5c31af7Sopenharmony_ci *//*--------------------------------------------------------------------*/
23e5c31af7Sopenharmony_ci
24e5c31af7Sopenharmony_ci#include "gluShaderProgram.hpp"
25e5c31af7Sopenharmony_ci#include "gluRenderContext.hpp"
26e5c31af7Sopenharmony_ci#include "glwFunctions.hpp"
27e5c31af7Sopenharmony_ci#include "glwEnums.hpp"
28e5c31af7Sopenharmony_ci#include "tcuTestLog.hpp"
29e5c31af7Sopenharmony_ci#include "deClock.h"
30e5c31af7Sopenharmony_ci
31e5c31af7Sopenharmony_ci#include <cstring>
32e5c31af7Sopenharmony_ci
33e5c31af7Sopenharmony_ciusing std::string;
34e5c31af7Sopenharmony_ci
35e5c31af7Sopenharmony_cinamespace glu
36e5c31af7Sopenharmony_ci{
37e5c31af7Sopenharmony_ci
38e5c31af7Sopenharmony_ci// Shader
39e5c31af7Sopenharmony_ci
40e5c31af7Sopenharmony_ciShader::Shader (const RenderContext& renderCtx, ShaderType shaderType)
41e5c31af7Sopenharmony_ci	: m_gl		(renderCtx.getFunctions())
42e5c31af7Sopenharmony_ci	, m_shader	(0)
43e5c31af7Sopenharmony_ci{
44e5c31af7Sopenharmony_ci	m_info.type	= shaderType;
45e5c31af7Sopenharmony_ci	m_shader	= m_gl.createShader(getGLShaderType(shaderType));
46e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCreateShader()");
47e5c31af7Sopenharmony_ci	TCU_CHECK(m_shader);
48e5c31af7Sopenharmony_ci}
49e5c31af7Sopenharmony_ci
50e5c31af7Sopenharmony_ciShader::Shader (const glw::Functions& gl, ShaderType shaderType)
51e5c31af7Sopenharmony_ci	: m_gl		(gl)
52e5c31af7Sopenharmony_ci	, m_shader	(0)
53e5c31af7Sopenharmony_ci{
54e5c31af7Sopenharmony_ci	m_info.type	= shaderType;
55e5c31af7Sopenharmony_ci	m_shader	= m_gl.createShader(getGLShaderType(shaderType));
56e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCreateShader()");
57e5c31af7Sopenharmony_ci	TCU_CHECK(m_shader);
58e5c31af7Sopenharmony_ci}
59e5c31af7Sopenharmony_ci
60e5c31af7Sopenharmony_ciShader::~Shader (void)
61e5c31af7Sopenharmony_ci{
62e5c31af7Sopenharmony_ci	m_gl.deleteShader(m_shader);
63e5c31af7Sopenharmony_ci}
64e5c31af7Sopenharmony_ci
65e5c31af7Sopenharmony_civoid Shader::setSources (int numSourceStrings, const char* const* sourceStrings, const int* lengths)
66e5c31af7Sopenharmony_ci{
67e5c31af7Sopenharmony_ci	m_gl.shaderSource(m_shader, numSourceStrings, sourceStrings, lengths);
68e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glShaderSource()");
69e5c31af7Sopenharmony_ci
70e5c31af7Sopenharmony_ci	m_info.source.clear();
71e5c31af7Sopenharmony_ci	for (int ndx = 0; ndx < numSourceStrings; ndx++)
72e5c31af7Sopenharmony_ci	{
73e5c31af7Sopenharmony_ci		const size_t length = lengths && lengths[ndx] >= 0 ? lengths[ndx] : strlen(sourceStrings[ndx]);
74e5c31af7Sopenharmony_ci		m_info.source += std::string(sourceStrings[ndx], length);
75e5c31af7Sopenharmony_ci	}
76e5c31af7Sopenharmony_ci}
77e5c31af7Sopenharmony_ci
78e5c31af7Sopenharmony_civoid Shader::compile (void)
79e5c31af7Sopenharmony_ci{
80e5c31af7Sopenharmony_ci	m_info.compileOk		= false;
81e5c31af7Sopenharmony_ci	m_info.compileTimeUs	= 0;
82e5c31af7Sopenharmony_ci	m_info.infoLog.clear();
83e5c31af7Sopenharmony_ci
84e5c31af7Sopenharmony_ci	{
85e5c31af7Sopenharmony_ci		deUint64 compileStart = deGetMicroseconds();
86e5c31af7Sopenharmony_ci		m_gl.compileShader(m_shader);
87e5c31af7Sopenharmony_ci		m_info.compileTimeUs = deGetMicroseconds() - compileStart;
88e5c31af7Sopenharmony_ci	}
89e5c31af7Sopenharmony_ci
90e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCompileShader()");
91e5c31af7Sopenharmony_ci
92e5c31af7Sopenharmony_ci	// Query status
93e5c31af7Sopenharmony_ci	{
94e5c31af7Sopenharmony_ci		int compileStatus = 0;
95e5c31af7Sopenharmony_ci
96e5c31af7Sopenharmony_ci		m_gl.getShaderiv(m_shader, GL_COMPILE_STATUS, &compileStatus);
97e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetShaderiv()");
98e5c31af7Sopenharmony_ci
99e5c31af7Sopenharmony_ci		m_info.compileOk = compileStatus != GL_FALSE;
100e5c31af7Sopenharmony_ci	}
101e5c31af7Sopenharmony_ci
102e5c31af7Sopenharmony_ci	// Query log
103e5c31af7Sopenharmony_ci	{
104e5c31af7Sopenharmony_ci		int infoLogLen = 0;
105e5c31af7Sopenharmony_ci		int unusedLen;
106e5c31af7Sopenharmony_ci
107e5c31af7Sopenharmony_ci		m_gl.getShaderiv(m_shader, GL_INFO_LOG_LENGTH, &infoLogLen);
108e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetShaderiv()");
109e5c31af7Sopenharmony_ci
110e5c31af7Sopenharmony_ci		if (infoLogLen > 0)
111e5c31af7Sopenharmony_ci		{
112e5c31af7Sopenharmony_ci			// The INFO_LOG_LENGTH query and the buffer query implementations have
113e5c31af7Sopenharmony_ci			// very commonly off-by-one errors. Try to work around these issues.
114e5c31af7Sopenharmony_ci
115e5c31af7Sopenharmony_ci			// add tolerance for off-by-one in log length, buffer write, and for terminator
116e5c31af7Sopenharmony_ci			std::vector<char> infoLog(infoLogLen + 3, '\0');
117e5c31af7Sopenharmony_ci
118e5c31af7Sopenharmony_ci			// claim buf size is one smaller to protect from off-by-one writing over buffer bounds
119e5c31af7Sopenharmony_ci			m_gl.getShaderInfoLog(m_shader, (int)infoLog.size() - 1, &unusedLen, &infoLog[0]);
120e5c31af7Sopenharmony_ci
121e5c31af7Sopenharmony_ci			if (infoLog[(int)(infoLog.size()) - 1] != '\0')
122e5c31af7Sopenharmony_ci			{
123e5c31af7Sopenharmony_ci				// return whole buffer if null terminator was overwritten
124e5c31af7Sopenharmony_ci				m_info.infoLog = std::string(&infoLog[0], infoLog.size());
125e5c31af7Sopenharmony_ci			}
126e5c31af7Sopenharmony_ci			else
127e5c31af7Sopenharmony_ci			{
128e5c31af7Sopenharmony_ci				// read as C string. infoLog is guaranteed to be 0-terminated
129e5c31af7Sopenharmony_ci				m_info.infoLog = std::string(&infoLog[0]);
130e5c31af7Sopenharmony_ci			}
131e5c31af7Sopenharmony_ci		}
132e5c31af7Sopenharmony_ci	}
133e5c31af7Sopenharmony_ci}
134e5c31af7Sopenharmony_ci
135e5c31af7Sopenharmony_civoid Shader::specialize (const char* entryPoint, glw::GLuint numSpecializationConstants,
136e5c31af7Sopenharmony_ci						 const glw::GLuint* constantIndex, const glw::GLuint* constantValue)
137e5c31af7Sopenharmony_ci{
138e5c31af7Sopenharmony_ci	m_info.compileOk		= false;
139e5c31af7Sopenharmony_ci	m_info.compileTimeUs	= 0;
140e5c31af7Sopenharmony_ci	m_info.infoLog.clear();
141e5c31af7Sopenharmony_ci
142e5c31af7Sopenharmony_ci	{
143e5c31af7Sopenharmony_ci		deUint64 compileStart = deGetMicroseconds();
144e5c31af7Sopenharmony_ci		m_gl.specializeShader(m_shader, entryPoint, numSpecializationConstants, constantIndex, constantValue);
145e5c31af7Sopenharmony_ci		m_info.compileTimeUs = deGetMicroseconds() - compileStart;
146e5c31af7Sopenharmony_ci	}
147e5c31af7Sopenharmony_ci
148e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glSpecializeShader()");
149e5c31af7Sopenharmony_ci
150e5c31af7Sopenharmony_ci	// Query status
151e5c31af7Sopenharmony_ci	{
152e5c31af7Sopenharmony_ci		int compileStatus = 0;
153e5c31af7Sopenharmony_ci
154e5c31af7Sopenharmony_ci		m_gl.getShaderiv(m_shader, GL_COMPILE_STATUS, &compileStatus);
155e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetShaderiv()");
156e5c31af7Sopenharmony_ci
157e5c31af7Sopenharmony_ci		m_info.compileOk = compileStatus != GL_FALSE;
158e5c31af7Sopenharmony_ci	}
159e5c31af7Sopenharmony_ci
160e5c31af7Sopenharmony_ci	// Query log
161e5c31af7Sopenharmony_ci	{
162e5c31af7Sopenharmony_ci		int infoLogLen = 0;
163e5c31af7Sopenharmony_ci		int unusedLen;
164e5c31af7Sopenharmony_ci
165e5c31af7Sopenharmony_ci		m_gl.getShaderiv(m_shader, GL_INFO_LOG_LENGTH, &infoLogLen);
166e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetShaderiv()");
167e5c31af7Sopenharmony_ci
168e5c31af7Sopenharmony_ci		if (infoLogLen > 0)
169e5c31af7Sopenharmony_ci		{
170e5c31af7Sopenharmony_ci			// The INFO_LOG_LENGTH query and the buffer query implementations have
171e5c31af7Sopenharmony_ci			// very commonly off-by-one errors. Try to work around these issues.
172e5c31af7Sopenharmony_ci
173e5c31af7Sopenharmony_ci			// add tolerance for off-by-one in log length, buffer write, and for terminator
174e5c31af7Sopenharmony_ci			std::vector<char> infoLog(infoLogLen + 3, '\0');
175e5c31af7Sopenharmony_ci
176e5c31af7Sopenharmony_ci			// claim buf size is one smaller to protect from off-by-one writing over buffer bounds
177e5c31af7Sopenharmony_ci			m_gl.getShaderInfoLog(m_shader, (int)infoLog.size() - 1, &unusedLen, &infoLog[0]);
178e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetShaderInfoLog()");
179e5c31af7Sopenharmony_ci
180e5c31af7Sopenharmony_ci			if (infoLog[(int)(infoLog.size()) - 1] != '\0')
181e5c31af7Sopenharmony_ci			{
182e5c31af7Sopenharmony_ci				// return whole buffer if null terminator was overwritten
183e5c31af7Sopenharmony_ci				m_info.infoLog = std::string(&infoLog[0], infoLog.size());
184e5c31af7Sopenharmony_ci			}
185e5c31af7Sopenharmony_ci			else
186e5c31af7Sopenharmony_ci			{
187e5c31af7Sopenharmony_ci				// read as C string. infoLog is guaranteed to be 0-terminated
188e5c31af7Sopenharmony_ci				m_info.infoLog = std::string(&infoLog[0]);
189e5c31af7Sopenharmony_ci			}
190e5c31af7Sopenharmony_ci		}
191e5c31af7Sopenharmony_ci	}
192e5c31af7Sopenharmony_ci}
193e5c31af7Sopenharmony_ci
194e5c31af7Sopenharmony_ci// Program
195e5c31af7Sopenharmony_ci
196e5c31af7Sopenharmony_cistatic bool getProgramLinkStatus (const glw::Functions& gl, deUint32 program)
197e5c31af7Sopenharmony_ci{
198e5c31af7Sopenharmony_ci	int	linkStatus				= 0;
199e5c31af7Sopenharmony_ci
200e5c31af7Sopenharmony_ci	gl.getProgramiv(program, GL_LINK_STATUS, &linkStatus);
201e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv()");
202e5c31af7Sopenharmony_ci	return (linkStatus != GL_FALSE);
203e5c31af7Sopenharmony_ci}
204e5c31af7Sopenharmony_ci
205e5c31af7Sopenharmony_cistatic std::string getProgramInfoLog (const glw::Functions& gl, deUint32 program)
206e5c31af7Sopenharmony_ci{
207e5c31af7Sopenharmony_ci	int infoLogLen = 0;
208e5c31af7Sopenharmony_ci	int unusedLen;
209e5c31af7Sopenharmony_ci
210e5c31af7Sopenharmony_ci	gl.getProgramiv(program, GL_INFO_LOG_LENGTH, &infoLogLen);
211e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv()");
212e5c31af7Sopenharmony_ci
213e5c31af7Sopenharmony_ci	if (infoLogLen > 0)
214e5c31af7Sopenharmony_ci	{
215e5c31af7Sopenharmony_ci		// The INFO_LOG_LENGTH query and the buffer query implementations have
216e5c31af7Sopenharmony_ci		// very commonly off-by-one errors. Try to work around these issues.
217e5c31af7Sopenharmony_ci
218e5c31af7Sopenharmony_ci		// add tolerance for off-by-one in log length, buffer write, and for terminator
219e5c31af7Sopenharmony_ci		std::vector<char> infoLog(infoLogLen + 3, '\0');
220e5c31af7Sopenharmony_ci
221e5c31af7Sopenharmony_ci		// claim buf size is one smaller to protect from off-by-one writing over buffer bounds
222e5c31af7Sopenharmony_ci		gl.getProgramInfoLog(program, (int)infoLog.size() - 1, &unusedLen, &infoLog[0]);
223e5c31af7Sopenharmony_ci
224e5c31af7Sopenharmony_ci		// return whole buffer if null terminator was overwritten
225e5c31af7Sopenharmony_ci		if (infoLog[(int)(infoLog.size()) - 1] != '\0')
226e5c31af7Sopenharmony_ci			return std::string(&infoLog[0], infoLog.size());
227e5c31af7Sopenharmony_ci
228e5c31af7Sopenharmony_ci		// read as C string. infoLog is guaranteed to be 0-terminated
229e5c31af7Sopenharmony_ci		return std::string(&infoLog[0]);
230e5c31af7Sopenharmony_ci	}
231e5c31af7Sopenharmony_ci	return std::string();
232e5c31af7Sopenharmony_ci}
233e5c31af7Sopenharmony_ci
234e5c31af7Sopenharmony_ciProgram::Program (const RenderContext& renderCtx)
235e5c31af7Sopenharmony_ci	: m_gl		(renderCtx.getFunctions())
236e5c31af7Sopenharmony_ci	, m_program	(0)
237e5c31af7Sopenharmony_ci{
238e5c31af7Sopenharmony_ci	m_program = m_gl.createProgram();
239e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCreateProgram()");
240e5c31af7Sopenharmony_ci}
241e5c31af7Sopenharmony_ci
242e5c31af7Sopenharmony_ciProgram::Program (const glw::Functions& gl)
243e5c31af7Sopenharmony_ci	: m_gl		(gl)
244e5c31af7Sopenharmony_ci	, m_program	(0)
245e5c31af7Sopenharmony_ci{
246e5c31af7Sopenharmony_ci	m_program = m_gl.createProgram();
247e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCreateProgram()");
248e5c31af7Sopenharmony_ci}
249e5c31af7Sopenharmony_ci
250e5c31af7Sopenharmony_ciProgram::Program (const RenderContext& renderCtx, deUint32 program)
251e5c31af7Sopenharmony_ci	: m_gl		(renderCtx.getFunctions())
252e5c31af7Sopenharmony_ci	, m_program	(program)
253e5c31af7Sopenharmony_ci{
254e5c31af7Sopenharmony_ci	m_info.linkOk	= getProgramLinkStatus(m_gl, program);
255e5c31af7Sopenharmony_ci	m_info.infoLog	= getProgramInfoLog(m_gl, program);
256e5c31af7Sopenharmony_ci}
257e5c31af7Sopenharmony_ci
258e5c31af7Sopenharmony_ciProgram::~Program (void)
259e5c31af7Sopenharmony_ci{
260e5c31af7Sopenharmony_ci	m_gl.deleteProgram(m_program);
261e5c31af7Sopenharmony_ci}
262e5c31af7Sopenharmony_ci
263e5c31af7Sopenharmony_civoid Program::attachShader (deUint32 shader)
264e5c31af7Sopenharmony_ci{
265e5c31af7Sopenharmony_ci	m_gl.attachShader(m_program, shader);
266e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glAttachShader()");
267e5c31af7Sopenharmony_ci}
268e5c31af7Sopenharmony_ci
269e5c31af7Sopenharmony_civoid Program::detachShader (deUint32 shader)
270e5c31af7Sopenharmony_ci{
271e5c31af7Sopenharmony_ci	m_gl.detachShader(m_program, shader);
272e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDetachShader()");
273e5c31af7Sopenharmony_ci}
274e5c31af7Sopenharmony_ci
275e5c31af7Sopenharmony_civoid Program::bindAttribLocation (deUint32 location, const char* name)
276e5c31af7Sopenharmony_ci{
277e5c31af7Sopenharmony_ci	m_gl.bindAttribLocation(m_program, location, name);
278e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindAttribLocation()");
279e5c31af7Sopenharmony_ci}
280e5c31af7Sopenharmony_ci
281e5c31af7Sopenharmony_civoid Program::transformFeedbackVaryings (int count, const char* const* varyings, deUint32 bufferMode)
282e5c31af7Sopenharmony_ci{
283e5c31af7Sopenharmony_ci	m_gl.transformFeedbackVaryings(m_program, count, varyings, bufferMode);
284e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glTransformFeedbackVaryings()");
285e5c31af7Sopenharmony_ci}
286e5c31af7Sopenharmony_ci
287e5c31af7Sopenharmony_civoid Program::link (void)
288e5c31af7Sopenharmony_ci{
289e5c31af7Sopenharmony_ci	m_info.linkOk		= false;
290e5c31af7Sopenharmony_ci	m_info.linkTimeUs	= 0;
291e5c31af7Sopenharmony_ci	m_info.infoLog.clear();
292e5c31af7Sopenharmony_ci
293e5c31af7Sopenharmony_ci	{
294e5c31af7Sopenharmony_ci		deUint64 linkStart = deGetMicroseconds();
295e5c31af7Sopenharmony_ci		m_gl.linkProgram(m_program);
296e5c31af7Sopenharmony_ci		m_info.linkTimeUs = deGetMicroseconds() - linkStart;
297e5c31af7Sopenharmony_ci	}
298e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glLinkProgram()");
299e5c31af7Sopenharmony_ci
300e5c31af7Sopenharmony_ci	m_info.linkOk	= getProgramLinkStatus(m_gl, m_program);
301e5c31af7Sopenharmony_ci	m_info.infoLog	= getProgramInfoLog(m_gl, m_program);
302e5c31af7Sopenharmony_ci}
303e5c31af7Sopenharmony_ci
304e5c31af7Sopenharmony_cibool Program::isSeparable (void) const
305e5c31af7Sopenharmony_ci{
306e5c31af7Sopenharmony_ci	int separable = GL_FALSE;
307e5c31af7Sopenharmony_ci
308e5c31af7Sopenharmony_ci	m_gl.getProgramiv(m_program, GL_PROGRAM_SEPARABLE, &separable);
309e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetProgramiv()");
310e5c31af7Sopenharmony_ci
311e5c31af7Sopenharmony_ci	return (separable != GL_FALSE);
312e5c31af7Sopenharmony_ci}
313e5c31af7Sopenharmony_ci
314e5c31af7Sopenharmony_civoid Program::setSeparable (bool separable)
315e5c31af7Sopenharmony_ci{
316e5c31af7Sopenharmony_ci	m_gl.programParameteri(m_program, GL_PROGRAM_SEPARABLE, separable);
317e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glProgramParameteri()");
318e5c31af7Sopenharmony_ci}
319e5c31af7Sopenharmony_ci
320e5c31af7Sopenharmony_ci// ProgramPipeline
321e5c31af7Sopenharmony_ci
322e5c31af7Sopenharmony_ciProgramPipeline::ProgramPipeline (const RenderContext& renderCtx)
323e5c31af7Sopenharmony_ci	: m_gl			(renderCtx.getFunctions())
324e5c31af7Sopenharmony_ci	, m_pipeline	(0)
325e5c31af7Sopenharmony_ci{
326e5c31af7Sopenharmony_ci	m_gl.genProgramPipelines(1, &m_pipeline);
327e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenProgramPipelines()");
328e5c31af7Sopenharmony_ci}
329e5c31af7Sopenharmony_ci
330e5c31af7Sopenharmony_ciProgramPipeline::ProgramPipeline (const glw::Functions& gl)
331e5c31af7Sopenharmony_ci	: m_gl			(gl)
332e5c31af7Sopenharmony_ci	, m_pipeline	(0)
333e5c31af7Sopenharmony_ci{
334e5c31af7Sopenharmony_ci	m_gl.genProgramPipelines(1, &m_pipeline);
335e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenProgramPipelines()");
336e5c31af7Sopenharmony_ci}
337e5c31af7Sopenharmony_ci
338e5c31af7Sopenharmony_ciProgramPipeline::~ProgramPipeline (void)
339e5c31af7Sopenharmony_ci{
340e5c31af7Sopenharmony_ci	m_gl.deleteProgramPipelines(1, &m_pipeline);
341e5c31af7Sopenharmony_ci}
342e5c31af7Sopenharmony_ci
343e5c31af7Sopenharmony_civoid ProgramPipeline::useProgramStages (deUint32 stages, deUint32 program)
344e5c31af7Sopenharmony_ci{
345e5c31af7Sopenharmony_ci	m_gl.useProgramStages(m_pipeline, stages, program);
346e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgramStages()");
347e5c31af7Sopenharmony_ci}
348e5c31af7Sopenharmony_ci
349e5c31af7Sopenharmony_civoid ProgramPipeline::activeShaderProgram (deUint32 program)
350e5c31af7Sopenharmony_ci{
351e5c31af7Sopenharmony_ci	m_gl.activeShaderProgram(m_pipeline, program);
352e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glActiveShaderProgram()");
353e5c31af7Sopenharmony_ci}
354e5c31af7Sopenharmony_ci
355e5c31af7Sopenharmony_cibool ProgramPipeline::isValid (void)
356e5c31af7Sopenharmony_ci{
357e5c31af7Sopenharmony_ci	glw::GLint status = GL_FALSE;
358e5c31af7Sopenharmony_ci	m_gl.validateProgramPipeline(m_pipeline);
359e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(m_gl.getError(), "glValidateProgramPipeline()");
360e5c31af7Sopenharmony_ci
361e5c31af7Sopenharmony_ci	m_gl.getProgramPipelineiv(m_pipeline, GL_VALIDATE_STATUS, &status);
362e5c31af7Sopenharmony_ci
363e5c31af7Sopenharmony_ci	return (status != GL_FALSE);
364e5c31af7Sopenharmony_ci}
365e5c31af7Sopenharmony_ci
366e5c31af7Sopenharmony_ci// ShaderProgram
367e5c31af7Sopenharmony_ci
368e5c31af7Sopenharmony_ciShaderProgram::ShaderProgram (const RenderContext& renderCtx, const ProgramSources& sources)
369e5c31af7Sopenharmony_ci	: m_program(renderCtx.getFunctions())
370e5c31af7Sopenharmony_ci{
371e5c31af7Sopenharmony_ci	init(renderCtx.getFunctions(), sources);
372e5c31af7Sopenharmony_ci}
373e5c31af7Sopenharmony_ci
374e5c31af7Sopenharmony_ciShaderProgram::ShaderProgram (const RenderContext& renderCtx, const ProgramBinaries& binaries)
375e5c31af7Sopenharmony_ci	: m_program(renderCtx.getFunctions())
376e5c31af7Sopenharmony_ci{
377e5c31af7Sopenharmony_ci	init(renderCtx.getFunctions(), binaries);
378e5c31af7Sopenharmony_ci}
379e5c31af7Sopenharmony_ci
380e5c31af7Sopenharmony_ciShaderProgram::ShaderProgram (const glw::Functions& gl, const ProgramSources& sources)
381e5c31af7Sopenharmony_ci	: m_program(gl)
382e5c31af7Sopenharmony_ci{
383e5c31af7Sopenharmony_ci	init(gl, sources);
384e5c31af7Sopenharmony_ci}
385e5c31af7Sopenharmony_ci
386e5c31af7Sopenharmony_ciShaderProgram::ShaderProgram (const glw::Functions& gl, const ProgramBinaries& binaries)
387e5c31af7Sopenharmony_ci	: m_program(gl)
388e5c31af7Sopenharmony_ci{
389e5c31af7Sopenharmony_ci	init(gl, binaries);
390e5c31af7Sopenharmony_ci}
391e5c31af7Sopenharmony_ci
392e5c31af7Sopenharmony_civoid ShaderProgram::init (const glw::Functions& gl, const ProgramSources& sources)
393e5c31af7Sopenharmony_ci{
394e5c31af7Sopenharmony_ci	try
395e5c31af7Sopenharmony_ci	{
396e5c31af7Sopenharmony_ci		bool shadersOk = true;
397e5c31af7Sopenharmony_ci
398e5c31af7Sopenharmony_ci		for (int shaderType = 0; shaderType < SHADERTYPE_LAST; shaderType++)
399e5c31af7Sopenharmony_ci		{
400e5c31af7Sopenharmony_ci			for (int shaderNdx = 0; shaderNdx < (int)sources.sources[shaderType].size(); ++shaderNdx)
401e5c31af7Sopenharmony_ci			{
402e5c31af7Sopenharmony_ci				const char* source	= sources.sources[shaderType][shaderNdx].c_str();
403e5c31af7Sopenharmony_ci				const int	length	= (int)sources.sources[shaderType][shaderNdx].size();
404e5c31af7Sopenharmony_ci
405e5c31af7Sopenharmony_ci				m_shaders[shaderType].reserve(m_shaders[shaderType].size() + 1);
406e5c31af7Sopenharmony_ci
407e5c31af7Sopenharmony_ci				m_shaders[shaderType].push_back(new Shader(gl, ShaderType(shaderType)));
408e5c31af7Sopenharmony_ci				m_shaders[shaderType].back()->setSources(1, &source, &length);
409e5c31af7Sopenharmony_ci				m_shaders[shaderType].back()->compile();
410e5c31af7Sopenharmony_ci
411e5c31af7Sopenharmony_ci				shadersOk = shadersOk && m_shaders[shaderType].back()->getCompileStatus();
412e5c31af7Sopenharmony_ci			}
413e5c31af7Sopenharmony_ci		}
414e5c31af7Sopenharmony_ci
415e5c31af7Sopenharmony_ci		if (shadersOk)
416e5c31af7Sopenharmony_ci		{
417e5c31af7Sopenharmony_ci			for (int shaderType = 0; shaderType < SHADERTYPE_LAST; shaderType++)
418e5c31af7Sopenharmony_ci				for (int shaderNdx = 0; shaderNdx < (int)m_shaders[shaderType].size(); ++shaderNdx)
419e5c31af7Sopenharmony_ci					m_program.attachShader(m_shaders[shaderType][shaderNdx]->getShader());
420e5c31af7Sopenharmony_ci
421e5c31af7Sopenharmony_ci			for (std::vector<AttribLocationBinding>::const_iterator binding = sources.attribLocationBindings.begin(); binding != sources.attribLocationBindings.end(); ++binding)
422e5c31af7Sopenharmony_ci				m_program.bindAttribLocation(binding->location, binding->name.c_str());
423e5c31af7Sopenharmony_ci
424e5c31af7Sopenharmony_ci			DE_ASSERT((sources.transformFeedbackBufferMode == GL_NONE) == sources.transformFeedbackVaryings.empty());
425e5c31af7Sopenharmony_ci			if (sources.transformFeedbackBufferMode != GL_NONE)
426e5c31af7Sopenharmony_ci			{
427e5c31af7Sopenharmony_ci				std::vector<const char*> tfVaryings(sources.transformFeedbackVaryings.size());
428e5c31af7Sopenharmony_ci				for (int ndx = 0; ndx < (int)tfVaryings.size(); ndx++)
429e5c31af7Sopenharmony_ci					tfVaryings[ndx] = sources.transformFeedbackVaryings[ndx].c_str();
430e5c31af7Sopenharmony_ci
431e5c31af7Sopenharmony_ci				m_program.transformFeedbackVaryings((int)tfVaryings.size(), &tfVaryings[0], sources.transformFeedbackBufferMode);
432e5c31af7Sopenharmony_ci			}
433e5c31af7Sopenharmony_ci
434e5c31af7Sopenharmony_ci			if (sources.separable)
435e5c31af7Sopenharmony_ci				m_program.setSeparable(true);
436e5c31af7Sopenharmony_ci
437e5c31af7Sopenharmony_ci			m_program.link();
438e5c31af7Sopenharmony_ci		}
439e5c31af7Sopenharmony_ci	}
440e5c31af7Sopenharmony_ci	catch (...)
441e5c31af7Sopenharmony_ci	{
442e5c31af7Sopenharmony_ci		for (int shaderType = 0; shaderType < SHADERTYPE_LAST; shaderType++)
443e5c31af7Sopenharmony_ci			for (int shaderNdx = 0; shaderNdx < (int)m_shaders[shaderType].size(); ++shaderNdx)
444e5c31af7Sopenharmony_ci				delete m_shaders[shaderType][shaderNdx];
445e5c31af7Sopenharmony_ci		throw;
446e5c31af7Sopenharmony_ci	}
447e5c31af7Sopenharmony_ci}
448e5c31af7Sopenharmony_ci
449e5c31af7Sopenharmony_civoid ShaderProgram::init (const glw::Functions& gl, const ProgramBinaries& binaries)
450e5c31af7Sopenharmony_ci{
451e5c31af7Sopenharmony_ci	try
452e5c31af7Sopenharmony_ci	{
453e5c31af7Sopenharmony_ci		bool shadersOk = true;
454e5c31af7Sopenharmony_ci
455e5c31af7Sopenharmony_ci		for (deUint32 binaryNdx = 0; binaryNdx < binaries.binaries.size(); ++binaryNdx)
456e5c31af7Sopenharmony_ci		{
457e5c31af7Sopenharmony_ci			ShaderBinary shaderBinary = binaries.binaries[binaryNdx];
458e5c31af7Sopenharmony_ci			if (!shaderBinary.binary.empty())
459e5c31af7Sopenharmony_ci			{
460e5c31af7Sopenharmony_ci				const char* binary	= (const char*)shaderBinary.binary.data();
461e5c31af7Sopenharmony_ci				const int	length	= (int)(shaderBinary.binary.size() * sizeof(deUint32));
462e5c31af7Sopenharmony_ci
463e5c31af7Sopenharmony_ci				DE_ASSERT(shaderBinary.shaderEntryPoints.size() == shaderBinary.shaderTypes.size());
464e5c31af7Sopenharmony_ci
465e5c31af7Sopenharmony_ci				std::vector<Shader*> shaders;
466e5c31af7Sopenharmony_ci				for (deUint32 shaderTypeNdx = 0; shaderTypeNdx < shaderBinary.shaderTypes.size(); ++shaderTypeNdx)
467e5c31af7Sopenharmony_ci				{
468e5c31af7Sopenharmony_ci					ShaderType shaderType = shaderBinary.shaderTypes[shaderTypeNdx];
469e5c31af7Sopenharmony_ci
470e5c31af7Sopenharmony_ci					Shader* shader = new Shader(gl, ShaderType(shaderType));
471e5c31af7Sopenharmony_ci
472e5c31af7Sopenharmony_ci					m_shaders[shaderType].reserve(m_shaders[shaderType].size() + 1);
473e5c31af7Sopenharmony_ci					m_shaders[shaderType].push_back(shader);
474e5c31af7Sopenharmony_ci					shaders.push_back(shader);
475e5c31af7Sopenharmony_ci				}
476e5c31af7Sopenharmony_ci
477e5c31af7Sopenharmony_ci				setBinary(gl, shaders, binaries.binaryFormat, binary, length);
478e5c31af7Sopenharmony_ci
479e5c31af7Sopenharmony_ci				for (deUint32 shaderNdx = 0; shaderNdx < shaders.size(); ++shaderNdx)
480e5c31af7Sopenharmony_ci				{
481e5c31af7Sopenharmony_ci					shaders[shaderNdx]->specialize(shaderBinary.shaderEntryPoints[shaderNdx].c_str(),
482e5c31af7Sopenharmony_ci												   (deUint32)shaderBinary.specializationIndices.size(),
483e5c31af7Sopenharmony_ci												   shaderBinary.specializationIndices.data(),
484e5c31af7Sopenharmony_ci												   shaderBinary.specializationValues.data());
485e5c31af7Sopenharmony_ci
486e5c31af7Sopenharmony_ci					shadersOk = shadersOk && shaders[shaderNdx]->getCompileStatus();
487e5c31af7Sopenharmony_ci				}
488e5c31af7Sopenharmony_ci			}
489e5c31af7Sopenharmony_ci		}
490e5c31af7Sopenharmony_ci
491e5c31af7Sopenharmony_ci		if (shadersOk)
492e5c31af7Sopenharmony_ci		{
493e5c31af7Sopenharmony_ci			for (int shaderType = 0; shaderType < SHADERTYPE_LAST; shaderType++)
494e5c31af7Sopenharmony_ci				for (int shaderNdx = 0; shaderNdx < (int)m_shaders[shaderType].size(); ++shaderNdx)
495e5c31af7Sopenharmony_ci					m_program.attachShader(m_shaders[shaderType][shaderNdx]->getShader());
496e5c31af7Sopenharmony_ci
497e5c31af7Sopenharmony_ci			m_program.link();
498e5c31af7Sopenharmony_ci		}
499e5c31af7Sopenharmony_ci	}
500e5c31af7Sopenharmony_ci	catch (...)
501e5c31af7Sopenharmony_ci	{
502e5c31af7Sopenharmony_ci		for (int shaderType = 0; shaderType < SHADERTYPE_LAST; shaderType++)
503e5c31af7Sopenharmony_ci			for (int shaderNdx = 0; shaderNdx < (int)m_shaders[shaderType].size(); ++shaderNdx)
504e5c31af7Sopenharmony_ci				delete m_shaders[shaderType][shaderNdx];
505e5c31af7Sopenharmony_ci		throw;
506e5c31af7Sopenharmony_ci	}
507e5c31af7Sopenharmony_ci}
508e5c31af7Sopenharmony_ci
509e5c31af7Sopenharmony_civoid ShaderProgram::setBinary (const glw::Functions& gl, std::vector<Shader*>& shaders, glw::GLenum binaryFormat, const void* binaryData, const int length)
510e5c31af7Sopenharmony_ci{
511e5c31af7Sopenharmony_ci	std::vector<glw::GLuint> shaderVec;
512e5c31af7Sopenharmony_ci	for (deUint32 shaderNdx = 0; shaderNdx < shaders.size(); ++shaderNdx)
513e5c31af7Sopenharmony_ci		shaderVec.push_back(shaders[shaderNdx]->getShader());
514e5c31af7Sopenharmony_ci
515e5c31af7Sopenharmony_ci	gl.shaderBinary((glw::GLsizei)shaderVec.size(), shaderVec.data(), binaryFormat, binaryData, length);
516e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderBinary");
517e5c31af7Sopenharmony_ci
518e5c31af7Sopenharmony_ci	for (deUint32 shaderNdx = 0; shaderNdx < shaders.size(); ++shaderNdx)
519e5c31af7Sopenharmony_ci	{
520e5c31af7Sopenharmony_ci		glw::GLint shaderState;
521e5c31af7Sopenharmony_ci		gl.getShaderiv(shaders[shaderNdx]->getShader(), GL_SPIR_V_BINARY_ARB, &shaderState);
522e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "getShaderiv");
523e5c31af7Sopenharmony_ci
524e5c31af7Sopenharmony_ci		DE_ASSERT(shaderState == GL_TRUE);
525e5c31af7Sopenharmony_ci	}
526e5c31af7Sopenharmony_ci}
527e5c31af7Sopenharmony_ci
528e5c31af7Sopenharmony_ciShaderProgram::~ShaderProgram (void)
529e5c31af7Sopenharmony_ci{
530e5c31af7Sopenharmony_ci	for (int shaderType = 0; shaderType < SHADERTYPE_LAST; shaderType++)
531e5c31af7Sopenharmony_ci		for (int shaderNdx = 0; shaderNdx < (int)m_shaders[shaderType].size(); ++shaderNdx)
532e5c31af7Sopenharmony_ci			delete m_shaders[shaderType][shaderNdx];
533e5c31af7Sopenharmony_ci}
534e5c31af7Sopenharmony_ci
535e5c31af7Sopenharmony_ci// Utilities
536e5c31af7Sopenharmony_ci
537e5c31af7Sopenharmony_cideUint32 getGLShaderType (ShaderType shaderType)
538e5c31af7Sopenharmony_ci{
539e5c31af7Sopenharmony_ci	static const deUint32 s_typeMap[] =
540e5c31af7Sopenharmony_ci	{
541e5c31af7Sopenharmony_ci		GL_VERTEX_SHADER,
542e5c31af7Sopenharmony_ci		GL_FRAGMENT_SHADER,
543e5c31af7Sopenharmony_ci		GL_GEOMETRY_SHADER,
544e5c31af7Sopenharmony_ci		GL_TESS_CONTROL_SHADER,
545e5c31af7Sopenharmony_ci		GL_TESS_EVALUATION_SHADER,
546e5c31af7Sopenharmony_ci		GL_COMPUTE_SHADER,
547e5c31af7Sopenharmony_ci		0,
548e5c31af7Sopenharmony_ci		0,
549e5c31af7Sopenharmony_ci		0,
550e5c31af7Sopenharmony_ci		0,
551e5c31af7Sopenharmony_ci		0,
552e5c31af7Sopenharmony_ci		0,
553e5c31af7Sopenharmony_ci		0,
554e5c31af7Sopenharmony_ci		0,
555e5c31af7Sopenharmony_ci	};
556e5c31af7Sopenharmony_ci	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_typeMap) == SHADERTYPE_LAST);
557e5c31af7Sopenharmony_ci	DE_ASSERT(de::inBounds<int>(shaderType, 0, DE_LENGTH_OF_ARRAY(s_typeMap)));
558e5c31af7Sopenharmony_ci	return s_typeMap[shaderType];
559e5c31af7Sopenharmony_ci}
560e5c31af7Sopenharmony_ci
561e5c31af7Sopenharmony_cideUint32 getGLShaderTypeBit (ShaderType shaderType)
562e5c31af7Sopenharmony_ci{
563e5c31af7Sopenharmony_ci	static const deUint32 s_typebitMap[] =
564e5c31af7Sopenharmony_ci	{
565e5c31af7Sopenharmony_ci		GL_VERTEX_SHADER_BIT,
566e5c31af7Sopenharmony_ci		GL_FRAGMENT_SHADER_BIT,
567e5c31af7Sopenharmony_ci		GL_GEOMETRY_SHADER_BIT,
568e5c31af7Sopenharmony_ci		GL_TESS_CONTROL_SHADER_BIT,
569e5c31af7Sopenharmony_ci		GL_TESS_EVALUATION_SHADER_BIT,
570e5c31af7Sopenharmony_ci		GL_COMPUTE_SHADER_BIT,
571e5c31af7Sopenharmony_ci		0,
572e5c31af7Sopenharmony_ci		0,
573e5c31af7Sopenharmony_ci		0,
574e5c31af7Sopenharmony_ci		0,
575e5c31af7Sopenharmony_ci		0,
576e5c31af7Sopenharmony_ci		0,
577e5c31af7Sopenharmony_ci		0,
578e5c31af7Sopenharmony_ci		0,
579e5c31af7Sopenharmony_ci	};
580e5c31af7Sopenharmony_ci	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_typebitMap) == SHADERTYPE_LAST);
581e5c31af7Sopenharmony_ci	DE_ASSERT(de::inBounds<int>(shaderType, 0, DE_LENGTH_OF_ARRAY(s_typebitMap)));
582e5c31af7Sopenharmony_ci	return s_typebitMap[shaderType];
583e5c31af7Sopenharmony_ci}
584e5c31af7Sopenharmony_ci
585e5c31af7Sopenharmony_ciqpShaderType getLogShaderType (ShaderType shaderType)
586e5c31af7Sopenharmony_ci{
587e5c31af7Sopenharmony_ci	static const qpShaderType s_typeMap[] =
588e5c31af7Sopenharmony_ci	{
589e5c31af7Sopenharmony_ci		QP_SHADER_TYPE_VERTEX,
590e5c31af7Sopenharmony_ci		QP_SHADER_TYPE_FRAGMENT,
591e5c31af7Sopenharmony_ci		QP_SHADER_TYPE_GEOMETRY,
592e5c31af7Sopenharmony_ci		QP_SHADER_TYPE_TESS_CONTROL,
593e5c31af7Sopenharmony_ci		QP_SHADER_TYPE_TESS_EVALUATION,
594e5c31af7Sopenharmony_ci		QP_SHADER_TYPE_COMPUTE,
595e5c31af7Sopenharmony_ci		QP_SHADER_TYPE_RAYGEN,
596e5c31af7Sopenharmony_ci		QP_SHADER_TYPE_ANY_HIT,
597e5c31af7Sopenharmony_ci		QP_SHADER_TYPE_CLOSEST_HIT,
598e5c31af7Sopenharmony_ci		QP_SHADER_TYPE_MISS,
599e5c31af7Sopenharmony_ci		QP_SHADER_TYPE_INTERSECTION,
600e5c31af7Sopenharmony_ci		QP_SHADER_TYPE_CALLABLE,
601e5c31af7Sopenharmony_ci		QP_SHADER_TYPE_TASK,
602e5c31af7Sopenharmony_ci		QP_SHADER_TYPE_MESH,
603e5c31af7Sopenharmony_ci	};
604e5c31af7Sopenharmony_ci	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_typeMap) == SHADERTYPE_LAST);
605e5c31af7Sopenharmony_ci	DE_ASSERT(de::inBounds<int>(shaderType, 0, DE_LENGTH_OF_ARRAY(s_typeMap)));
606e5c31af7Sopenharmony_ci	return s_typeMap[shaderType];
607e5c31af7Sopenharmony_ci}
608e5c31af7Sopenharmony_ci
609e5c31af7Sopenharmony_citcu::TestLog& operator<< (tcu::TestLog& log, const ShaderInfo& shaderInfo)
610e5c31af7Sopenharmony_ci{
611e5c31af7Sopenharmony_ci	return log << tcu::TestLog::Shader(getLogShaderType(shaderInfo.type), shaderInfo.source, shaderInfo.compileOk, shaderInfo.infoLog);
612e5c31af7Sopenharmony_ci}
613e5c31af7Sopenharmony_ci
614e5c31af7Sopenharmony_citcu::TestLog& operator<< (tcu::TestLog& log, const Shader& shader)
615e5c31af7Sopenharmony_ci{
616e5c31af7Sopenharmony_ci	return log << tcu::TestLog::ShaderProgram(false, "Plain shader") << shader.getInfo() << tcu::TestLog::EndShaderProgram;
617e5c31af7Sopenharmony_ci}
618e5c31af7Sopenharmony_ci
619e5c31af7Sopenharmony_cistatic void logShaderProgram (tcu::TestLog& log, const ProgramInfo& programInfo, size_t numShaders, const ShaderInfo* const* shaderInfos)
620e5c31af7Sopenharmony_ci{
621e5c31af7Sopenharmony_ci	log << tcu::TestLog::ShaderProgram(programInfo.linkOk, programInfo.infoLog);
622e5c31af7Sopenharmony_ci	try
623e5c31af7Sopenharmony_ci	{
624e5c31af7Sopenharmony_ci		for (size_t shaderNdx = 0; shaderNdx < numShaders; ++shaderNdx)
625e5c31af7Sopenharmony_ci			log << *shaderInfos[shaderNdx];
626e5c31af7Sopenharmony_ci	}
627e5c31af7Sopenharmony_ci	catch (...)
628e5c31af7Sopenharmony_ci	{
629e5c31af7Sopenharmony_ci		log << tcu::TestLog::EndShaderProgram;
630e5c31af7Sopenharmony_ci		throw;
631e5c31af7Sopenharmony_ci	}
632e5c31af7Sopenharmony_ci	log << tcu::TestLog::EndShaderProgram;
633e5c31af7Sopenharmony_ci
634e5c31af7Sopenharmony_ci	// Write statistics.
635e5c31af7Sopenharmony_ci	{
636e5c31af7Sopenharmony_ci		static const struct
637e5c31af7Sopenharmony_ci		{
638e5c31af7Sopenharmony_ci			const char*		name;
639e5c31af7Sopenharmony_ci			const char*		description;
640e5c31af7Sopenharmony_ci		} s_compileTimeDesc[] =
641e5c31af7Sopenharmony_ci		{
642e5c31af7Sopenharmony_ci			{ "VertexCompileTime",			"Vertex shader compile time"					},
643e5c31af7Sopenharmony_ci			{ "FragmentCompileTime",		"Fragment shader compile time"					},
644e5c31af7Sopenharmony_ci			{ "GeometryCompileTime",		"Geometry shader compile time"					},
645e5c31af7Sopenharmony_ci			{ "TessControlCompileTime",		"Tesselation control shader compile time"		},
646e5c31af7Sopenharmony_ci			{ "TessEvaluationCompileTime",	"Tesselation evaluation shader compile time"	},
647e5c31af7Sopenharmony_ci			{ "ComputeCompileTime",			"Compute shader compile time"					},
648e5c31af7Sopenharmony_ci			{ "RaygenCompileTime",			"Raygen shader compile time"					},
649e5c31af7Sopenharmony_ci			{ "AnyHitCompileTime",			"Any hit shader compile time"					},
650e5c31af7Sopenharmony_ci			{ "ClosestHitCompileTime",		"Closest hit shader compile time"				},
651e5c31af7Sopenharmony_ci			{ "MissCompileTime",			"Miss shader compile time"						},
652e5c31af7Sopenharmony_ci			{ "IntersectionCompileTime",	"Intersection shader compile time"				},
653e5c31af7Sopenharmony_ci			{ "CallableCompileTime",		"Callable shader compile time"					},
654e5c31af7Sopenharmony_ci			{ "TaskCompileTime",			"Task shader compile time"						},
655e5c31af7Sopenharmony_ci			{ "MeshCompileTime",			"Mesh shader compile time"						},
656e5c31af7Sopenharmony_ci		};
657e5c31af7Sopenharmony_ci		DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_compileTimeDesc) == SHADERTYPE_LAST);
658e5c31af7Sopenharmony_ci
659e5c31af7Sopenharmony_ci		bool allShadersOk = true;
660e5c31af7Sopenharmony_ci
661e5c31af7Sopenharmony_ci		for (size_t shaderNdx = 0; shaderNdx < numShaders; ++shaderNdx)
662e5c31af7Sopenharmony_ci		{
663e5c31af7Sopenharmony_ci			const ShaderInfo&	shaderInfo	= *shaderInfos[shaderNdx];
664e5c31af7Sopenharmony_ci
665e5c31af7Sopenharmony_ci			log << tcu::TestLog::Float(s_compileTimeDesc[shaderInfo.type].name,
666e5c31af7Sopenharmony_ci									   s_compileTimeDesc[shaderInfo.type].description,
667e5c31af7Sopenharmony_ci									   "ms", QP_KEY_TAG_TIME, (float)shaderInfo.compileTimeUs / 1000.0f);
668e5c31af7Sopenharmony_ci
669e5c31af7Sopenharmony_ci			allShadersOk = allShadersOk && shaderInfo.compileOk;
670e5c31af7Sopenharmony_ci		}
671e5c31af7Sopenharmony_ci
672e5c31af7Sopenharmony_ci		if (allShadersOk)
673e5c31af7Sopenharmony_ci			log << tcu::TestLog::Float("LinkTime", "Link time", "ms", QP_KEY_TAG_TIME, (float)programInfo.linkTimeUs / 1000.0f);
674e5c31af7Sopenharmony_ci	}
675e5c31af7Sopenharmony_ci}
676e5c31af7Sopenharmony_ci
677e5c31af7Sopenharmony_citcu::TestLog& operator<< (tcu::TestLog& log, const ShaderProgramInfo& shaderProgramInfo)
678e5c31af7Sopenharmony_ci{
679e5c31af7Sopenharmony_ci	std::vector<const ShaderInfo*>	shaderPtrs	(shaderProgramInfo.shaders.size());
680e5c31af7Sopenharmony_ci
681e5c31af7Sopenharmony_ci	for (size_t ndx = 0; ndx < shaderPtrs.size(); ndx++)
682e5c31af7Sopenharmony_ci		shaderPtrs[ndx] = &shaderProgramInfo.shaders[ndx];
683e5c31af7Sopenharmony_ci
684e5c31af7Sopenharmony_ci	logShaderProgram(log, shaderProgramInfo.program, shaderPtrs.size(), shaderPtrs.empty() ? DE_NULL : &shaderPtrs[0]);
685e5c31af7Sopenharmony_ci
686e5c31af7Sopenharmony_ci	return log;
687e5c31af7Sopenharmony_ci}
688e5c31af7Sopenharmony_ci
689e5c31af7Sopenharmony_citcu::TestLog& operator<< (tcu::TestLog& log, const ShaderProgram& shaderProgram)
690e5c31af7Sopenharmony_ci{
691e5c31af7Sopenharmony_ci	std::vector<const ShaderInfo*>	shaderPtrs;
692e5c31af7Sopenharmony_ci
693e5c31af7Sopenharmony_ci	for (int shaderType = 0; shaderType < SHADERTYPE_LAST; shaderType++)
694e5c31af7Sopenharmony_ci	{
695e5c31af7Sopenharmony_ci		for (int shaderNdx = 0; shaderNdx < shaderProgram.getNumShaders((ShaderType)shaderType); shaderNdx++)
696e5c31af7Sopenharmony_ci			shaderPtrs.push_back(&shaderProgram.getShaderInfo((ShaderType)shaderType, shaderNdx));
697e5c31af7Sopenharmony_ci	}
698e5c31af7Sopenharmony_ci
699e5c31af7Sopenharmony_ci	logShaderProgram(log, shaderProgram.getProgramInfo(), shaderPtrs.size(), shaderPtrs.empty() ? DE_NULL : &shaderPtrs[0]);
700e5c31af7Sopenharmony_ci
701e5c31af7Sopenharmony_ci	return log;
702e5c31af7Sopenharmony_ci}
703e5c31af7Sopenharmony_ci
704e5c31af7Sopenharmony_citcu::TestLog& operator<< (tcu::TestLog& log, const ProgramSources& sources)
705e5c31af7Sopenharmony_ci{
706e5c31af7Sopenharmony_ci	log << tcu::TestLog::ShaderProgram(false, "(Source only)");
707e5c31af7Sopenharmony_ci
708e5c31af7Sopenharmony_ci	try
709e5c31af7Sopenharmony_ci	{
710e5c31af7Sopenharmony_ci		for (int shaderType = 0; shaderType < SHADERTYPE_LAST; shaderType++)
711e5c31af7Sopenharmony_ci		{
712e5c31af7Sopenharmony_ci			for (size_t shaderNdx = 0; shaderNdx < sources.sources[shaderType].size(); shaderNdx++)
713e5c31af7Sopenharmony_ci			{
714e5c31af7Sopenharmony_ci				log << tcu::TestLog::Shader(getLogShaderType((ShaderType)shaderType),
715e5c31af7Sopenharmony_ci											sources.sources[shaderType][shaderNdx],
716e5c31af7Sopenharmony_ci											false, "");
717e5c31af7Sopenharmony_ci			}
718e5c31af7Sopenharmony_ci		}
719e5c31af7Sopenharmony_ci	}
720e5c31af7Sopenharmony_ci	catch (...)
721e5c31af7Sopenharmony_ci	{
722e5c31af7Sopenharmony_ci		log << tcu::TestLog::EndShaderProgram;
723e5c31af7Sopenharmony_ci		throw;
724e5c31af7Sopenharmony_ci	}
725e5c31af7Sopenharmony_ci
726e5c31af7Sopenharmony_ci	log << tcu::TestLog::EndShaderProgram;
727e5c31af7Sopenharmony_ci
728e5c31af7Sopenharmony_ci	return log;
729e5c31af7Sopenharmony_ci}
730e5c31af7Sopenharmony_ci
731e5c31af7Sopenharmony_ci} // glu
732