1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES Utilities
3  * ------------------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Reference Rendering Context.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "sglrReferenceContext.hpp"
25 #include "sglrReferenceUtils.hpp"
26 #include "sglrShaderProgram.hpp"
27 #include "tcuTextureUtil.hpp"
28 #include "tcuMatrix.hpp"
29 #include "tcuMatrixUtil.hpp"
30 #include "tcuVectorUtil.hpp"
31 #include "gluDefs.hpp"
32 #include "gluTextureUtil.hpp"
33 #include "gluContextInfo.hpp"
34 #include "glwFunctions.hpp"
35 #include "glwEnums.hpp"
36 #include "deMemory.h"
37 #include "rrFragmentOperations.hpp"
38 #include "rrRenderer.hpp"
39 
40 #include <cstdint>
41 
42 namespace sglr
43 {
44 
45 using std::vector;
46 using std::map;
47 
48 using tcu::Vec2;
49 using tcu::Vec3;
50 using tcu::Vec4;
51 using tcu::IVec2;
52 using tcu::IVec4;
53 using tcu::RGBA;
54 
55 // Reference context implementation
56 using namespace rc;
57 
58 using tcu::TextureFormat;
59 using tcu::PixelBufferAccess;
60 using tcu::ConstPixelBufferAccess;
61 
62 // Utilities for ReferenceContext
63 #define RC_RET_VOID
64 
65 #define RC_ERROR_RET(ERR, RET)			\
66 do {									\
67 	setError(ERR);						\
68 	return RET;							\
69 } while (deGetFalse())
70 
71 #define RC_IF_ERROR(COND, ERR, RET)		\
72 do {									\
73 	if (COND)							\
74 		RC_ERROR_RET(ERR, RET);			\
75 } while (deGetFalse())
76 
nullAccess(void)77 static inline tcu::PixelBufferAccess nullAccess (void)
78 {
79 	return tcu::PixelBufferAccess(TextureFormat(TextureFormat::R, TextureFormat::UNSIGNED_INT8), 0, 0, 0, DE_NULL);
80 }
81 
isEmpty(const tcu::ConstPixelBufferAccess& access)82 static inline bool isEmpty (const tcu::ConstPixelBufferAccess& access)
83 {
84 	return access.getWidth() == 0 || access.getHeight() == 0 || access.getDepth() == 0;
85 }
86 
isEmpty(const rr::MultisampleConstPixelBufferAccess& access)87 static inline bool isEmpty (const rr::MultisampleConstPixelBufferAccess& access)
88 {
89 	return access.raw().getWidth() == 0 || access.raw().getHeight() == 0 || access.raw().getDepth() == 0;
90 }
91 
isEmpty(const IVec4& rect)92 static inline bool isEmpty (const IVec4& rect)
93 {
94 	return rect.z() == 0 || rect.w() == 0;
95 }
96 
getNumMipLevels1D(int size)97 inline int getNumMipLevels1D (int size)
98 {
99 	return deLog2Floor32(size)+1;
100 }
101 
getNumMipLevels2D(int width, int height)102 inline int getNumMipLevels2D (int width, int height)
103 {
104 	return deLog2Floor32(de::max(width, height))+1;
105 }
106 
getNumMipLevels3D(int width, int height, int depth)107 inline int getNumMipLevels3D (int width, int height, int depth)
108 {
109 	return deLog2Floor32(de::max(width, de::max(height, depth)))+1;
110 }
111 
getMipLevelSize(int baseLevelSize, int levelNdx)112 inline int getMipLevelSize (int baseLevelSize, int levelNdx)
113 {
114 	return de::max(baseLevelSize >> levelNdx, 1);
115 }
116 
isMipmapFilter(const tcu::Sampler::FilterMode mode)117 inline bool isMipmapFilter (const tcu::Sampler::FilterMode mode)
118 {
119 	return mode != tcu::Sampler::NEAREST && mode != tcu::Sampler::LINEAR;
120 }
121 
texTargetToFace(Framebuffer::TexTarget target)122 static tcu::CubeFace texTargetToFace (Framebuffer::TexTarget target)
123 {
124 	switch (target)
125 	{
126 		case Framebuffer::TEXTARGET_CUBE_MAP_NEGATIVE_X:	return tcu::CUBEFACE_NEGATIVE_X;
127 		case Framebuffer::TEXTARGET_CUBE_MAP_POSITIVE_X:	return tcu::CUBEFACE_POSITIVE_X;
128 		case Framebuffer::TEXTARGET_CUBE_MAP_NEGATIVE_Y:	return tcu::CUBEFACE_NEGATIVE_Y;
129 		case Framebuffer::TEXTARGET_CUBE_MAP_POSITIVE_Y:	return tcu::CUBEFACE_POSITIVE_Y;
130 		case Framebuffer::TEXTARGET_CUBE_MAP_NEGATIVE_Z:	return tcu::CUBEFACE_NEGATIVE_Z;
131 		case Framebuffer::TEXTARGET_CUBE_MAP_POSITIVE_Z:	return tcu::CUBEFACE_POSITIVE_Z;
132 		default:											return tcu::CUBEFACE_LAST;
133 	}
134 }
135 
texLayeredTypeToTarget(Texture::Type type)136 static Framebuffer::TexTarget texLayeredTypeToTarget (Texture::Type type)
137 {
138 	switch (type)
139 	{
140 		case Texture::TYPE_2D_ARRAY:		return Framebuffer::TEXTARGET_2D_ARRAY;
141 		case Texture::TYPE_3D:				return Framebuffer::TEXTARGET_3D;
142 		case Texture::TYPE_CUBE_MAP_ARRAY:	return Framebuffer::TEXTARGET_CUBE_MAP_ARRAY;
143 		default:							return Framebuffer::TEXTARGET_LAST;
144 	}
145 }
146 
mapGLCubeFace(deUint32 face)147 static tcu::CubeFace mapGLCubeFace (deUint32 face)
148 {
149 	switch (face)
150 	{
151 		case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:	return tcu::CUBEFACE_NEGATIVE_X;
152 		case GL_TEXTURE_CUBE_MAP_POSITIVE_X:	return tcu::CUBEFACE_POSITIVE_X;
153 		case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:	return tcu::CUBEFACE_NEGATIVE_Y;
154 		case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:	return tcu::CUBEFACE_POSITIVE_Y;
155 		case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:	return tcu::CUBEFACE_NEGATIVE_Z;
156 		case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:	return tcu::CUBEFACE_POSITIVE_Z;
157 		default:								return tcu::CUBEFACE_LAST;
158 	}
159 }
160 
toTextureFormat(const tcu::PixelFormat& pixelFmt)161 tcu::TextureFormat toTextureFormat (const tcu::PixelFormat& pixelFmt)
162 {
163 	static const struct
164 	{
165 		tcu::PixelFormat	pixelFmt;
166 		tcu::TextureFormat	texFmt;
167 	} pixelFormatMap[] =
168 	{
169 		{ tcu::PixelFormat(8,8,8,8),	tcu::TextureFormat(tcu::TextureFormat::RGBA,	tcu::TextureFormat::UNORM_INT8)			},
170 		{ tcu::PixelFormat(8,8,8,0),	tcu::TextureFormat(tcu::TextureFormat::RGB,		tcu::TextureFormat::UNORM_INT8)			},
171 		{ tcu::PixelFormat(4,4,4,4),	tcu::TextureFormat(tcu::TextureFormat::RGBA,	tcu::TextureFormat::UNORM_SHORT_4444)	},
172 		{ tcu::PixelFormat(5,5,5,1),	tcu::TextureFormat(tcu::TextureFormat::RGBA,	tcu::TextureFormat::UNORM_SHORT_5551)	},
173 		{ tcu::PixelFormat(5,6,5,0),	tcu::TextureFormat(tcu::TextureFormat::RGB,		tcu::TextureFormat::UNORM_SHORT_565)	}
174 	};
175 
176 	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(pixelFormatMap); ndx++)
177 	{
178 		if (pixelFormatMap[ndx].pixelFmt == pixelFmt)
179 			return pixelFormatMap[ndx].texFmt;
180 	}
181 
182 	TCU_FAIL("Can't map pixel format to texture format");
183 }
184 
toNonSRGBFormat(const tcu::TextureFormat& fmt)185 tcu::TextureFormat toNonSRGBFormat (const tcu::TextureFormat& fmt)
186 {
187 	switch (fmt.order)
188 	{
189 		case tcu::TextureFormat::sRGB:
190 			return tcu::TextureFormat(tcu::TextureFormat::RGB,	fmt.type);
191 		case tcu::TextureFormat::sRGBA:
192 			return tcu::TextureFormat(tcu::TextureFormat::RGBA,	fmt.type);
193 		default:
194 			return fmt;
195 	}
196 }
197 
getDepthFormat(int depthBits)198 tcu::TextureFormat getDepthFormat (int depthBits)
199 {
200 	switch (depthBits)
201 	{
202 		case 8:		return tcu::TextureFormat(tcu::TextureFormat::D, tcu::TextureFormat::UNORM_INT8);
203 		case 16:	return tcu::TextureFormat(tcu::TextureFormat::D, tcu::TextureFormat::UNORM_INT16);
204 		case 24:	return tcu::TextureFormat(tcu::TextureFormat::D, tcu::TextureFormat::UNSIGNED_INT_24_8);
205 		case 32:	return tcu::TextureFormat(tcu::TextureFormat::D, tcu::TextureFormat::FLOAT);
206 		default:
207 			TCU_FAIL("Can't map depth buffer format");
208 	}
209 }
210 
getStencilFormat(int stencilBits)211 tcu::TextureFormat getStencilFormat (int stencilBits)
212 {
213 	switch (stencilBits)
214 	{
215 		case 8:		return tcu::TextureFormat(tcu::TextureFormat::S, tcu::TextureFormat::UNSIGNED_INT8);
216 		case 16:	return tcu::TextureFormat(tcu::TextureFormat::S, tcu::TextureFormat::UNSIGNED_INT16);
217 		case 24:	return tcu::TextureFormat(tcu::TextureFormat::S, tcu::TextureFormat::UNSIGNED_INT_24_8);
218 		case 32:	return tcu::TextureFormat(tcu::TextureFormat::S, tcu::TextureFormat::UNSIGNED_INT32);
219 		default:
220 			TCU_FAIL("Can't map depth buffer format");
221 	}
222 }
223 
intersect(const tcu::IVec4& a, const tcu::IVec4& b)224 static inline tcu::IVec4 intersect (const tcu::IVec4& a, const tcu::IVec4& b)
225 {
226 	int		x0	= de::max(a.x(), b.x());
227 	int		y0	= de::max(a.y(), b.y());
228 	int		x1	= de::min(a.x()+a.z(), b.x()+b.z());
229 	int		y1	= de::min(a.y()+a.w(), b.y()+b.w());
230 	int		w	= de::max(0, x1-x0);
231 	int		h	= de::max(0, y1-y0);
232 
233 	return tcu::IVec4(x0, y0, w, h);
234 }
235 
getBufferRect(const rr::MultisampleConstPixelBufferAccess& access)236 static inline tcu::IVec4 getBufferRect (const rr::MultisampleConstPixelBufferAccess& access)
237 {
238 	return tcu::IVec4(0, 0, access.raw().getHeight(), access.raw().getDepth());
239 }
240 
ReferenceContextLimits(const glu::RenderContext& renderCtx)241 ReferenceContextLimits::ReferenceContextLimits (const glu::RenderContext& renderCtx)
242 	: contextType				(renderCtx.getType())
243 	, maxTextureImageUnits		(0)
244 	, maxTexture2DSize			(0)
245 	, maxTextureCubeSize		(0)
246 	, maxTexture2DArrayLayers	(0)
247 	, maxTexture3DSize			(0)
248 	, maxRenderbufferSize		(0)
249 	, maxVertexAttribs			(0)
250 	, subpixelBits				(0)
251 {
252 	const glw::Functions& gl = renderCtx.getFunctions();
253 
254 	// When the OpenGL ES's major version bigger than 3, and the expect context version is 3,
255 	// we need query the real GL context version and update the real version to reference context.
256 	if (glu::IsES3Compatible(gl) && isES2Context(contextType))
257 	{
258 		int majorVersion = contextType.getMajorVersion();
259 		int minorVersion = contextType.getMinorVersion();
260 		gl.getIntegerv(GL_MAJOR_VERSION, &majorVersion);
261 		gl.getIntegerv(GL_MINOR_VERSION, &minorVersion);
262 		contextType.setAPI(glu::ApiType::es(majorVersion, minorVersion));
263 	}
264 
265 	gl.getIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS,		&maxTextureImageUnits);
266 	gl.getIntegerv(GL_MAX_TEXTURE_SIZE,				&maxTexture2DSize);
267 	gl.getIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE,	&maxTextureCubeSize);
268 	gl.getIntegerv(GL_MAX_RENDERBUFFER_SIZE,		&maxRenderbufferSize);
269 	gl.getIntegerv(GL_MAX_VERTEX_ATTRIBS,			&maxVertexAttribs);
270 	gl.getIntegerv(GL_SUBPIXEL_BITS,				&subpixelBits);
271 
272 	if (contextSupports(contextType, glu::ApiType::es(3,0)) || glu::isContextTypeGLCore(contextType))
273 	{
274 		gl.getIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS,	&maxTexture2DArrayLayers);
275 		gl.getIntegerv(GL_MAX_3D_TEXTURE_SIZE,		&maxTexture3DSize);
276 	}
277 
278 	// Limit texture sizes to supported values
279 	maxTexture2DSize	= de::min(maxTexture2DSize,		(int)MAX_TEXTURE_SIZE);
280 	maxTextureCubeSize	= de::min(maxTextureCubeSize,	(int)MAX_TEXTURE_SIZE);
281 	maxTexture3DSize	= de::min(maxTexture3DSize,		(int)MAX_TEXTURE_SIZE);
282 
283 	GLU_EXPECT_NO_ERROR(gl.getError(), GL_NO_ERROR);
284 
285 	// \todo [pyry] Figure out following things:
286 	// + supported fbo configurations
287 	// ...
288 
289 	// \todo [2013-08-01 pyry] Do we want to make these conditional based on renderCtx?
290 	addExtension("GL_EXT_color_buffer_half_float");
291 	addExtension("GL_EXT_color_buffer_float");
292 
293 	if (contextSupports(contextType, glu::ApiType::es(3,1)))
294 		addExtension("GL_EXT_texture_cube_map_array");
295 }
296 
addExtension(const char* extension)297 void ReferenceContextLimits::addExtension (const char* extension)
298 {
299 	extensionList.push_back(extension);
300 
301 	if (!extensionStr.empty())
302 		extensionStr += " ";
303 	extensionStr += extension;
304 }
305 
ReferenceContextBuffers(const tcu::PixelFormat& colorBits, int depthBits, int stencilBits, int width, int height, int samples)306 ReferenceContextBuffers::ReferenceContextBuffers (const tcu::PixelFormat& colorBits, int depthBits, int stencilBits, int width, int height, int samples)
307 {
308 	m_colorbuffer.setStorage(toTextureFormat(colorBits), samples, width, height);
309 
310 	if (depthBits > 0)
311 		m_depthbuffer.setStorage(getDepthFormat(depthBits), samples, width, height);
312 
313 	if (stencilBits > 0)
314 		m_stencilbuffer.setStorage(getStencilFormat(stencilBits), samples, width, height);
315 }
316 
StencilState(void)317 ReferenceContext::StencilState::StencilState (void)
318 	: func				(GL_ALWAYS)
319 	, ref				(0)
320 	, opMask			(~0u)
321 	, opStencilFail		(GL_KEEP)
322 	, opDepthFail		(GL_KEEP)
323 	, opDepthPass		(GL_KEEP)
324 	, writeMask			(~0u)
325 {
326 }
327 
ReferenceContext(const ReferenceContextLimits& limits, const rr::MultisamplePixelBufferAccess& colorbuffer, const rr::MultisamplePixelBufferAccess& depthbuffer, const rr::MultisamplePixelBufferAccess& stencilbuffer)328 ReferenceContext::ReferenceContext (const ReferenceContextLimits& limits, const rr::MultisamplePixelBufferAccess& colorbuffer, const rr::MultisamplePixelBufferAccess& depthbuffer, const rr::MultisamplePixelBufferAccess& stencilbuffer)
329 	: Context							(limits.contextType)
330 	, m_limits							(limits)
331 	, m_defaultColorbuffer				(colorbuffer)
332 	, m_defaultDepthbuffer				(depthbuffer)
333 	, m_defaultStencilbuffer			(stencilbuffer)
334 	, m_clientVertexArray				(0, m_limits.maxVertexAttribs)
335 
336 	, m_viewport						(0, 0, colorbuffer.raw().getHeight(), colorbuffer.raw().getDepth())
337 
338 	, m_activeTexture					(0)
339 	, m_textureUnits					(m_limits.maxTextureImageUnits)
340 	, m_emptyTex1D						()
341 	, m_emptyTex2D						(isES2Context(limits.contextType))
342 	, m_emptyTexCube					(!isES2Context(limits.contextType))
343 	, m_emptyTex2DArray					()
344 	, m_emptyTex3D						()
345 	, m_emptyTexCubeArray				()
346 
347 	, m_pixelUnpackRowLength			(0)
348 	, m_pixelUnpackSkipRows				(0)
349 	, m_pixelUnpackSkipPixels			(0)
350 	, m_pixelUnpackImageHeight			(0)
351 	, m_pixelUnpackSkipImages			(0)
352 	, m_pixelUnpackAlignment			(4)
353 	, m_pixelPackAlignment				(4)
354 
355 	, m_readFramebufferBinding			(DE_NULL)
356 	, m_drawFramebufferBinding			(DE_NULL)
357 	, m_renderbufferBinding				(DE_NULL)
358 	, m_vertexArrayBinding				(DE_NULL)
359 	, m_currentProgram					(DE_NULL)
360 
361 	, m_arrayBufferBinding				(DE_NULL)
362 	, m_pixelPackBufferBinding			(DE_NULL)
363 	, m_pixelUnpackBufferBinding		(DE_NULL)
364 	, m_transformFeedbackBufferBinding	(DE_NULL)
365 	, m_uniformBufferBinding			(DE_NULL)
366 	, m_copyReadBufferBinding			(DE_NULL)
367 	, m_copyWriteBufferBinding			(DE_NULL)
368 	, m_drawIndirectBufferBinding		(DE_NULL)
369 
370 	, m_clearColor						(0.0f, 0.0f, 0.0f, 0.0f)
371 	, m_clearDepth						(1.0f)
372 	, m_clearStencil					(0)
373 	, m_scissorEnabled					(false)
374 	, m_scissorBox						(m_viewport)
375 	, m_stencilTestEnabled				(false)
376 	, m_depthTestEnabled				(false)
377 	, m_depthFunc						(GL_LESS)
378 	, m_depthRangeNear					(0.0f)
379 	, m_depthRangeFar					(1.0f)
380 	, m_polygonOffsetFactor				(0.0f)
381 	, m_polygonOffsetUnits				(0.0f)
382 	, m_polygonOffsetFillEnabled		(false)
383 	, m_provokingFirstVertexConvention	(false)
384 	, m_blendEnabled					(false)
385 	, m_blendModeRGB					(GL_FUNC_ADD)
386 	, m_blendModeAlpha					(GL_FUNC_ADD)
387 	, m_blendFactorSrcRGB				(GL_ONE)
388 	, m_blendFactorDstRGB				(GL_ZERO)
389 	, m_blendFactorSrcAlpha				(GL_ONE)
390 	, m_blendFactorDstAlpha				(GL_ZERO)
391 	, m_blendColor						(0.0f, 0.0f, 0.0f, 0.0f)
392 	, m_sRGBUpdateEnabled				(true)
393 	, m_depthClampEnabled				(false)
394 	, m_colorMask						(true, true, true, true)
395 	, m_depthMask						(true)
396 	, m_currentAttribs					(m_limits.maxVertexAttribs, rr::GenericVec4(tcu::Vec4(0, 0, 0, 1)))
397 	, m_lineWidth						(1.0f)
398 	, m_primitiveRestartFixedIndex		(false)
399 	, m_primitiveRestartSettableIndex	(false)
400 	, m_primitiveRestartIndex			(0)
401 
402 	, m_lastError						(GL_NO_ERROR)
403 {
404 	// Create empty textures to be used when texture objects are incomplete.
405 	m_emptyTex1D.getSampler().wrapS		= tcu::Sampler::CLAMP_TO_EDGE;
406 	m_emptyTex1D.getSampler().wrapT		= tcu::Sampler::CLAMP_TO_EDGE;
407 	m_emptyTex1D.getSampler().minFilter	= tcu::Sampler::NEAREST;
408 	m_emptyTex1D.getSampler().magFilter	= tcu::Sampler::NEAREST;
409 	m_emptyTex1D.allocLevel(0, tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), 1);
410 	m_emptyTex1D.getLevel(0).setPixel(Vec4(0.0f, 0.0f, 0.0f, 1.0f), 0, 0);
411 	m_emptyTex1D.updateView(tcu::Sampler::MODE_LAST);
412 
413 	m_emptyTex2D.getSampler().wrapS		= tcu::Sampler::CLAMP_TO_EDGE;
414 	m_emptyTex2D.getSampler().wrapT		= tcu::Sampler::CLAMP_TO_EDGE;
415 	m_emptyTex2D.getSampler().minFilter	= tcu::Sampler::NEAREST;
416 	m_emptyTex2D.getSampler().magFilter	= tcu::Sampler::NEAREST;
417 	m_emptyTex2D.allocLevel(0, tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), 1, 1);
418 	m_emptyTex2D.getLevel(0).setPixel(Vec4(0.0f, 0.0f, 0.0f, 1.0f), 0, 0);
419 	m_emptyTex2D.updateView(tcu::Sampler::MODE_LAST);
420 
421 	m_emptyTexCube.getSampler().wrapS		= tcu::Sampler::CLAMP_TO_EDGE;
422 	m_emptyTexCube.getSampler().wrapT		= tcu::Sampler::CLAMP_TO_EDGE;
423 	m_emptyTexCube.getSampler().minFilter	= tcu::Sampler::NEAREST;
424 	m_emptyTexCube.getSampler().magFilter	= tcu::Sampler::NEAREST;
425 	for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
426 	{
427 		m_emptyTexCube.allocFace(0, (tcu::CubeFace)face, tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), 1, 1);
428 		m_emptyTexCube.getFace(0, (tcu::CubeFace)face).setPixel(Vec4(0.0f, 0.0f, 0.0f, 1.0f), 0, 0);
429 	}
430 	m_emptyTexCube.updateView(tcu::Sampler::MODE_LAST);
431 
432 	m_emptyTex2DArray.getSampler().wrapS		= tcu::Sampler::CLAMP_TO_EDGE;
433 	m_emptyTex2DArray.getSampler().wrapT		= tcu::Sampler::CLAMP_TO_EDGE;
434 	m_emptyTex2DArray.getSampler().minFilter	= tcu::Sampler::NEAREST;
435 	m_emptyTex2DArray.getSampler().magFilter	= tcu::Sampler::NEAREST;
436 	m_emptyTex2DArray.allocLevel(0, tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), 1, 1, 1);
437 	m_emptyTex2DArray.getLevel(0).setPixel(Vec4(0.0f, 0.0f, 0.0f, 1.0f), 0, 0);
438 	m_emptyTex2DArray.updateView(tcu::Sampler::MODE_LAST);
439 
440 	m_emptyTex3D.getSampler().wrapS		= tcu::Sampler::CLAMP_TO_EDGE;
441 	m_emptyTex3D.getSampler().wrapT		= tcu::Sampler::CLAMP_TO_EDGE;
442 	m_emptyTex3D.getSampler().wrapR		= tcu::Sampler::CLAMP_TO_EDGE;
443 	m_emptyTex3D.getSampler().minFilter	= tcu::Sampler::NEAREST;
444 	m_emptyTex3D.getSampler().magFilter	= tcu::Sampler::NEAREST;
445 	m_emptyTex3D.allocLevel(0, tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), 1, 1, 1);
446 	m_emptyTex3D.getLevel(0).setPixel(Vec4(0.0f, 0.0f, 0.0f, 1.0f), 0, 0);
447 	m_emptyTex3D.updateView(tcu::Sampler::MODE_LAST);
448 
449 	m_emptyTexCubeArray.getSampler().wrapS		= tcu::Sampler::CLAMP_TO_EDGE;
450 	m_emptyTexCubeArray.getSampler().wrapT		= tcu::Sampler::CLAMP_TO_EDGE;
451 	m_emptyTexCubeArray.getSampler().minFilter	= tcu::Sampler::NEAREST;
452 	m_emptyTexCubeArray.getSampler().magFilter	= tcu::Sampler::NEAREST;
453 	m_emptyTexCubeArray.allocLevel(0, tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), 1, 1, 6);
454 	for (int faceNdx = 0; faceNdx < 6; faceNdx++)
455 		m_emptyTexCubeArray.getLevel(0).setPixel(Vec4(0.0f, 0.0f, 0.0f, 1.0f), 0, 0, faceNdx);
456 	m_emptyTexCubeArray.updateView(tcu::Sampler::MODE_LAST);
457 
458 	for (int unitNdx = 0; unitNdx < m_limits.maxTextureImageUnits; unitNdx++)
459 		m_textureUnits[unitNdx].defaultCubeTex.getSampler().seamlessCubeMap = !isES2Context(limits.contextType);
460 
461 	if (glu::isContextTypeGLCore(getType()))
462 		m_sRGBUpdateEnabled = false;
463 }
464 
~ReferenceContext(void)465 ReferenceContext::~ReferenceContext (void)
466 {
467 	// Destroy all objects -- verifies that ref counting works
468 	{
469 		vector<VertexArray*> vertexArrays;
470 		m_vertexArrays.getAll(vertexArrays);
471 		for (vector<VertexArray*>::iterator i = vertexArrays.begin(); i != vertexArrays.end(); i++)
472 			deleteVertexArray(*i);
473 
474 		DE_ASSERT(m_clientVertexArray.getRefCount() == 1);
475 	}
476 
477 	{
478 		vector<Texture*> textures;
479 		m_textures.getAll(textures);
480 		for (vector<Texture*>::iterator i = textures.begin(); i != textures.end(); i++)
481 			deleteTexture(*i);
482 	}
483 
484 	{
485 		vector<Framebuffer*> framebuffers;
486 		m_framebuffers.getAll(framebuffers);
487 		for (vector<Framebuffer*>::iterator i = framebuffers.begin(); i != framebuffers.end(); i++)
488 			deleteFramebuffer(*i);
489 	}
490 
491 	{
492 		vector<Renderbuffer*> renderbuffers;
493 		m_renderbuffers.getAll(renderbuffers);
494 		for (vector<Renderbuffer*>::iterator i = renderbuffers.begin(); i != renderbuffers.end(); i++)
495 			deleteRenderbuffer(*i);
496 	}
497 
498 	{
499 		vector<DataBuffer*> buffers;
500 		m_buffers.getAll(buffers);
501 		for (vector<DataBuffer*>::iterator i = buffers.begin(); i != buffers.end(); i++)
502 			deleteBuffer(*i);
503 	}
504 
505 	{
506 		vector<ShaderProgramObjectContainer*> programs;
507 		m_programs.getAll(programs);
508 		for (vector<ShaderProgramObjectContainer*>::iterator i = programs.begin(); i != programs.end(); i++)
509 			deleteProgramObject(*i);
510 	}
511 }
512 
activeTexture(deUint32 texture)513 void ReferenceContext::activeTexture (deUint32 texture)
514 {
515 	if (deInBounds32(texture, GL_TEXTURE0, GL_TEXTURE0 + (deUint32)m_textureUnits.size()))
516 		m_activeTexture = texture - GL_TEXTURE0;
517 	else
518 		setError(GL_INVALID_ENUM);
519 }
520 
setTex1DBinding(int unitNdx, Texture1D* texture)521 void ReferenceContext::setTex1DBinding (int unitNdx, Texture1D* texture)
522 {
523 	if (m_textureUnits[unitNdx].tex1DBinding)
524 	{
525 		m_textures.releaseReference(m_textureUnits[unitNdx].tex1DBinding);
526 		m_textureUnits[unitNdx].tex1DBinding = DE_NULL;
527 	}
528 
529 	if (texture)
530 	{
531 		m_textures.acquireReference(texture);
532 		m_textureUnits[unitNdx].tex1DBinding = texture;
533 	}
534 }
535 
setTex2DBinding(int unitNdx, Texture2D* texture)536 void ReferenceContext::setTex2DBinding (int unitNdx, Texture2D* texture)
537 {
538 	if (m_textureUnits[unitNdx].tex2DBinding)
539 	{
540 		m_textures.releaseReference(m_textureUnits[unitNdx].tex2DBinding);
541 		m_textureUnits[unitNdx].tex2DBinding = DE_NULL;
542 	}
543 
544 	if (texture)
545 	{
546 		m_textures.acquireReference(texture);
547 		m_textureUnits[unitNdx].tex2DBinding = texture;
548 	}
549 }
550 
setTexCubeBinding(int unitNdx, TextureCube* texture)551 void ReferenceContext::setTexCubeBinding (int unitNdx, TextureCube* texture)
552 {
553 	if (m_textureUnits[unitNdx].texCubeBinding)
554 	{
555 		m_textures.releaseReference(m_textureUnits[unitNdx].texCubeBinding);
556 		m_textureUnits[unitNdx].texCubeBinding = DE_NULL;
557 	}
558 
559 	if (texture)
560 	{
561 		m_textures.acquireReference(texture);
562 		m_textureUnits[unitNdx].texCubeBinding = texture;
563 	}
564 }
565 
setTex2DArrayBinding(int unitNdx, Texture2DArray* texture)566 void ReferenceContext::setTex2DArrayBinding (int unitNdx, Texture2DArray* texture)
567 {
568 	if (m_textureUnits[unitNdx].tex2DArrayBinding)
569 	{
570 		m_textures.releaseReference(m_textureUnits[unitNdx].tex2DArrayBinding);
571 		m_textureUnits[unitNdx].tex2DArrayBinding = DE_NULL;
572 	}
573 
574 	if (texture)
575 	{
576 		m_textures.acquireReference(texture);
577 		m_textureUnits[unitNdx].tex2DArrayBinding = texture;
578 	}
579 }
580 
setTex3DBinding(int unitNdx, Texture3D* texture)581 void ReferenceContext::setTex3DBinding (int unitNdx, Texture3D* texture)
582 {
583 	if (m_textureUnits[unitNdx].tex3DBinding)
584 	{
585 		m_textures.releaseReference(m_textureUnits[unitNdx].tex3DBinding);
586 		m_textureUnits[unitNdx].tex3DBinding = DE_NULL;
587 	}
588 
589 	if (texture)
590 	{
591 		m_textures.acquireReference(texture);
592 		m_textureUnits[unitNdx].tex3DBinding = texture;
593 	}
594 }
595 
setTexCubeArrayBinding(int unitNdx, TextureCubeArray* texture)596 void ReferenceContext::setTexCubeArrayBinding (int unitNdx, TextureCubeArray* texture)
597 {
598 	if (m_textureUnits[unitNdx].texCubeArrayBinding)
599 	{
600 		m_textures.releaseReference(m_textureUnits[unitNdx].texCubeArrayBinding);
601 		m_textureUnits[unitNdx].texCubeArrayBinding = DE_NULL;
602 	}
603 
604 	if (texture)
605 	{
606 		m_textures.acquireReference(texture);
607 		m_textureUnits[unitNdx].texCubeArrayBinding = texture;
608 	}
609 }
610 
bindTexture(deUint32 target, deUint32 texture)611 void ReferenceContext::bindTexture (deUint32 target, deUint32 texture)
612 {
613 	int unitNdx = m_activeTexture;
614 
615 	RC_IF_ERROR(target != GL_TEXTURE_1D				&&
616 				target != GL_TEXTURE_2D				&&
617 				target != GL_TEXTURE_CUBE_MAP		&&
618 				target != GL_TEXTURE_2D_ARRAY		&&
619 				target != GL_TEXTURE_3D				&&
620 				target != GL_TEXTURE_CUBE_MAP_ARRAY,
621 				GL_INVALID_ENUM, RC_RET_VOID);
622 
623 	RC_IF_ERROR(glu::isContextTypeES(m_limits.contextType) && (target == GL_TEXTURE_1D), GL_INVALID_ENUM, RC_RET_VOID);
624 
625 	if (texture == 0)
626 	{
627 		// Clear binding.
628 		switch (target)
629 		{
630 			case GL_TEXTURE_1D:				setTex1DBinding			(unitNdx, DE_NULL);	break;
631 			case GL_TEXTURE_2D:				setTex2DBinding			(unitNdx, DE_NULL);	break;
632 			case GL_TEXTURE_CUBE_MAP:		setTexCubeBinding		(unitNdx, DE_NULL);	break;
633 			case GL_TEXTURE_2D_ARRAY:		setTex2DArrayBinding	(unitNdx, DE_NULL);	break;
634 			case GL_TEXTURE_3D:				setTex3DBinding			(unitNdx, DE_NULL);	break;
635 			case GL_TEXTURE_CUBE_MAP_ARRAY:	setTexCubeArrayBinding	(unitNdx, DE_NULL);	break;
636 			default:
637 				DE_ASSERT(false);
638 		}
639 	}
640 	else
641 	{
642 		Texture* texObj = m_textures.find(texture);
643 
644 		if (texObj)
645 		{
646 			// Validate type.
647 			Texture::Type expectedType = Texture::TYPE_LAST;
648 			switch (target)
649 			{
650 				case GL_TEXTURE_1D:				expectedType = Texture::TYPE_1D;				break;
651 				case GL_TEXTURE_2D:				expectedType = Texture::TYPE_2D;				break;
652 				case GL_TEXTURE_CUBE_MAP:		expectedType = Texture::TYPE_CUBE_MAP;			break;
653 				case GL_TEXTURE_2D_ARRAY:		expectedType = Texture::TYPE_2D_ARRAY;			break;
654 				case GL_TEXTURE_3D:				expectedType = Texture::TYPE_3D;				break;
655 				case GL_TEXTURE_CUBE_MAP_ARRAY:	expectedType = Texture::TYPE_CUBE_MAP_ARRAY;	break;
656 				default:
657 					DE_ASSERT(false);
658 			}
659 			RC_IF_ERROR(texObj->getType() != expectedType, GL_INVALID_OPERATION, RC_RET_VOID);
660 		}
661 		else
662 		{
663 			// New texture object.
664 			bool seamlessCubeMap = !isES2Context(m_limits.contextType);
665 			switch (target)
666 			{
667 				case GL_TEXTURE_1D:				texObj = new Texture1D			(texture);					break;
668 				case GL_TEXTURE_2D:				texObj = new Texture2D			(texture);					break;
669 				case GL_TEXTURE_CUBE_MAP:		texObj = new TextureCube		(texture, seamlessCubeMap);	break;
670 				case GL_TEXTURE_2D_ARRAY:		texObj = new Texture2DArray		(texture);					break;
671 				case GL_TEXTURE_3D:				texObj = new Texture3D			(texture);					break;
672 				case GL_TEXTURE_CUBE_MAP_ARRAY:	texObj = new TextureCubeArray	(texture);					break;
673 				default:
674 					DE_ASSERT(false);
675 			}
676 
677 			m_textures.insert(texObj);
678 		}
679 
680 		switch (target)
681 		{
682 			case GL_TEXTURE_1D:				setTex1DBinding			(unitNdx, static_cast<Texture1D*>			(texObj));	break;
683 			case GL_TEXTURE_2D:				setTex2DBinding			(unitNdx, static_cast<Texture2D*>			(texObj));	break;
684 			case GL_TEXTURE_CUBE_MAP:		setTexCubeBinding		(unitNdx, static_cast<TextureCube*>			(texObj));	break;
685 			case GL_TEXTURE_2D_ARRAY:		setTex2DArrayBinding	(unitNdx, static_cast<Texture2DArray*>		(texObj));	break;
686 			case GL_TEXTURE_3D:				setTex3DBinding			(unitNdx, static_cast<Texture3D*>			(texObj));	break;
687 			case GL_TEXTURE_CUBE_MAP_ARRAY:	setTexCubeArrayBinding	(unitNdx, static_cast<TextureCubeArray*>	(texObj));	break;
688 			default:
689 				DE_ASSERT(false);
690 		}
691 	}
692 }
693 
genTextures(int numTextures, deUint32* textures)694 void ReferenceContext::genTextures (int numTextures, deUint32* textures)
695 {
696 	while (numTextures--)
697 		*textures++ = m_textures.allocateName();
698 }
699 
deleteTextures(int numTextures, const deUint32* textures)700 void ReferenceContext::deleteTextures (int numTextures, const deUint32* textures)
701 {
702 	for (int i = 0; i < numTextures; i++)
703 	{
704 		deUint32	name		= textures[i];
705 		Texture*	texture		= name ? m_textures.find(name) : DE_NULL;
706 
707 		if (texture)
708 			deleteTexture(texture);
709 	}
710 }
711 
deleteTexture(Texture* texture)712 void ReferenceContext::deleteTexture (Texture* texture)
713 {
714 	// Unbind from context
715 	for (int unitNdx = 0; unitNdx < (int)m_textureUnits.size(); unitNdx++)
716 	{
717 		if (m_textureUnits[unitNdx].tex1DBinding				== texture)	setTex1DBinding			(unitNdx, DE_NULL);
718 		else if (m_textureUnits[unitNdx].tex2DBinding			== texture)	setTex2DBinding			(unitNdx, DE_NULL);
719 		else if (m_textureUnits[unitNdx].texCubeBinding			== texture)	setTexCubeBinding		(unitNdx, DE_NULL);
720 		else if (m_textureUnits[unitNdx].tex2DArrayBinding		== texture)	setTex2DArrayBinding	(unitNdx, DE_NULL);
721 		else if (m_textureUnits[unitNdx].tex3DBinding			== texture)	setTex3DBinding			(unitNdx, DE_NULL);
722 		else if (m_textureUnits[unitNdx].texCubeArrayBinding	== texture)	setTexCubeArrayBinding	(unitNdx, DE_NULL);
723 	}
724 
725 	// Unbind from currently bound framebuffers
726 	for (int ndx = 0; ndx < 2; ndx++)
727 	{
728 		rc::Framebuffer* framebufferBinding = ndx ? m_drawFramebufferBinding : m_readFramebufferBinding;
729 		if (framebufferBinding)
730 		{
731 			int releaseRefCount = (framebufferBinding == m_drawFramebufferBinding ? 1 : 0)
732 								+ (framebufferBinding == m_readFramebufferBinding ? 1 : 0);
733 
734 			for (int point = 0; point < Framebuffer::ATTACHMENTPOINT_LAST; point++)
735 			{
736 				Framebuffer::Attachment& attachment = framebufferBinding->getAttachment((Framebuffer::AttachmentPoint)point);
737 				if (attachment.name == texture->getName())
738 				{
739 					for (int refNdx = 0; refNdx < releaseRefCount; refNdx++)
740 						releaseFboAttachmentReference(attachment);
741 					attachment = Framebuffer::Attachment();
742 				}
743 			}
744 		}
745 	}
746 
747 	DE_ASSERT(texture->getRefCount() == 1);
748 	m_textures.releaseReference(texture);
749 }
750 
bindFramebuffer(deUint32 target, deUint32 name)751 void ReferenceContext::bindFramebuffer (deUint32 target, deUint32 name)
752 {
753 	Framebuffer* fbo = DE_NULL;
754 
755 	RC_IF_ERROR(target != GL_FRAMEBUFFER		&&
756 				target != GL_DRAW_FRAMEBUFFER	&&
757 				target != GL_READ_FRAMEBUFFER, GL_INVALID_ENUM, RC_RET_VOID);
758 
759 	if (name != 0)
760 	{
761 		// Find or create framebuffer object.
762 		fbo = m_framebuffers.find(name);
763 		if (!fbo)
764 		{
765 			fbo = new Framebuffer(name);
766 			m_framebuffers.insert(fbo);
767 		}
768 	}
769 
770 	for (int ndx = 0; ndx < 2; ndx++)
771 	{
772 		deUint32			bindingTarget	= ndx ? GL_DRAW_FRAMEBUFFER			: GL_READ_FRAMEBUFFER;
773 		rc::Framebuffer*&	binding			= ndx ? m_drawFramebufferBinding	: m_readFramebufferBinding;
774 
775 		if (target != GL_FRAMEBUFFER && target != bindingTarget)
776 			continue; // Doesn't match this target.
777 
778 		// Remove old references
779 		if (binding)
780 		{
781 			// Clear all attachment point references
782 			for (int point = 0; point < Framebuffer::ATTACHMENTPOINT_LAST; point++)
783 				releaseFboAttachmentReference(binding->getAttachment((Framebuffer::AttachmentPoint)point));
784 
785 			m_framebuffers.releaseReference(binding);
786 		}
787 
788 		// Create new references
789 		if (fbo)
790 		{
791 			m_framebuffers.acquireReference(fbo);
792 
793 			for (int point = 0; point < Framebuffer::ATTACHMENTPOINT_LAST; point++)
794 				acquireFboAttachmentReference(fbo->getAttachment((Framebuffer::AttachmentPoint)point));
795 		}
796 
797 		binding = fbo;
798 	}
799 }
800 
genFramebuffers(int numFramebuffers, deUint32* framebuffers)801 void ReferenceContext::genFramebuffers (int numFramebuffers, deUint32* framebuffers)
802 {
803 	while (numFramebuffers--)
804 		*framebuffers++ = m_framebuffers.allocateName();
805 }
806 
deleteFramebuffer(Framebuffer* framebuffer)807 void ReferenceContext::deleteFramebuffer (Framebuffer* framebuffer)
808 {
809 	// Remove bindings.
810 	if (m_drawFramebufferBinding == framebuffer) bindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
811 	if (m_readFramebufferBinding == framebuffer) bindFramebuffer(GL_READ_FRAMEBUFFER, 0);
812 
813 	DE_ASSERT(framebuffer->getRefCount() == 1);
814 	m_framebuffers.releaseReference(framebuffer);
815 }
816 
deleteFramebuffers(int numFramebuffers, const deUint32* framebuffers)817 void ReferenceContext::deleteFramebuffers (int numFramebuffers, const deUint32* framebuffers)
818 {
819 	for (int i = 0; i < numFramebuffers; i++)
820 	{
821 		deUint32		name		= framebuffers[i];
822 		Framebuffer*	framebuffer	= name ? m_framebuffers.find(name) : DE_NULL;
823 
824 		if (framebuffer)
825 			deleteFramebuffer(framebuffer);
826 	}
827 }
828 
bindRenderbuffer(deUint32 target, deUint32 name)829 void ReferenceContext::bindRenderbuffer (deUint32 target, deUint32 name)
830 {
831 	Renderbuffer* rbo = DE_NULL;
832 
833 	RC_IF_ERROR(target != GL_RENDERBUFFER, GL_INVALID_ENUM, RC_RET_VOID);
834 
835 	if (name != 0)
836 	{
837 		rbo = m_renderbuffers.find(name);
838 		if (!rbo)
839 		{
840 			rbo = new Renderbuffer(name);
841 			m_renderbuffers.insert(rbo);
842 		}
843 	}
844 
845 	// Remove old reference
846 	if (m_renderbufferBinding)
847 		m_renderbuffers.releaseReference(m_renderbufferBinding);
848 
849 	// Create new reference
850 	if (rbo)
851 		m_renderbuffers.acquireReference(rbo);
852 
853 	m_renderbufferBinding = rbo;
854 }
855 
genRenderbuffers(int numRenderbuffers, deUint32* renderbuffers)856 void ReferenceContext::genRenderbuffers (int numRenderbuffers, deUint32* renderbuffers)
857 {
858 	while (numRenderbuffers--)
859 		*renderbuffers++ = m_renderbuffers.allocateName();
860 }
861 
deleteRenderbuffer(Renderbuffer* renderbuffer)862 void ReferenceContext::deleteRenderbuffer (Renderbuffer* renderbuffer)
863 {
864 	if (m_renderbufferBinding == renderbuffer)
865 		bindRenderbuffer(GL_RENDERBUFFER, 0);
866 
867 	// Unbind from currently bound framebuffers
868 	for (int ndx = 0; ndx < 2; ndx++)
869 	{
870 		rc::Framebuffer* framebufferBinding = ndx ? m_drawFramebufferBinding : m_readFramebufferBinding;
871 		if (framebufferBinding)
872 		{
873 			int releaseRefCount = (framebufferBinding == m_drawFramebufferBinding ? 1 : 0)
874 								+ (framebufferBinding == m_readFramebufferBinding ? 1 : 0);
875 
876 			for (int point = 0; point < Framebuffer::ATTACHMENTPOINT_LAST; point++)
877 			{
878 				Framebuffer::Attachment& attachment = framebufferBinding->getAttachment((Framebuffer::AttachmentPoint)point);
879 				if (attachment.name == renderbuffer->getName())
880 				{
881 					for (int refNdx = 0; refNdx < releaseRefCount; refNdx++)
882 						releaseFboAttachmentReference(attachment);
883 					attachment = Framebuffer::Attachment();
884 				}
885 			}
886 		}
887 	}
888 
889 	DE_ASSERT(renderbuffer->getRefCount() == 1);
890 	m_renderbuffers.releaseReference(renderbuffer);
891 }
892 
deleteRenderbuffers(int numRenderbuffers, const deUint32* renderbuffers)893 void ReferenceContext::deleteRenderbuffers (int numRenderbuffers, const deUint32* renderbuffers)
894 {
895 	for (int i = 0; i < numRenderbuffers; i++)
896 	{
897 		deUint32		name			= renderbuffers[i];
898 		Renderbuffer*	renderbuffer	= name ? m_renderbuffers.find(name) : DE_NULL;
899 
900 		if (renderbuffer)
901 			deleteRenderbuffer(renderbuffer);
902 	}
903 }
904 
pixelStorei(deUint32 pname, int param)905 void ReferenceContext::pixelStorei (deUint32 pname, int param)
906 {
907 	switch (pname)
908 	{
909 		case GL_UNPACK_ALIGNMENT:
910 			RC_IF_ERROR(param != 1 && param != 2 && param != 4 && param != 8, GL_INVALID_VALUE, RC_RET_VOID);
911 			m_pixelUnpackAlignment = param;
912 			break;
913 
914 		case GL_PACK_ALIGNMENT:
915 			RC_IF_ERROR(param != 1 && param != 2 && param != 4 && param != 8, GL_INVALID_VALUE, RC_RET_VOID);
916 			m_pixelPackAlignment = param;
917 			break;
918 
919 		case GL_UNPACK_ROW_LENGTH:
920 			RC_IF_ERROR(param < 0, GL_INVALID_VALUE, RC_RET_VOID);
921 			m_pixelUnpackRowLength = param;
922 			break;
923 
924 		case GL_UNPACK_SKIP_ROWS:
925 			RC_IF_ERROR(param < 0, GL_INVALID_VALUE, RC_RET_VOID);
926 			m_pixelUnpackSkipRows = param;
927 			break;
928 
929 		case GL_UNPACK_SKIP_PIXELS:
930 			RC_IF_ERROR(param < 0, GL_INVALID_VALUE, RC_RET_VOID);
931 			m_pixelUnpackSkipPixels = param;
932 			break;
933 
934 		case GL_UNPACK_IMAGE_HEIGHT:
935 			RC_IF_ERROR(param < 0, GL_INVALID_VALUE, RC_RET_VOID);
936 			m_pixelUnpackImageHeight = param;
937 			break;
938 
939 		case GL_UNPACK_SKIP_IMAGES:
940 			RC_IF_ERROR(param < 0, GL_INVALID_VALUE, RC_RET_VOID);
941 			m_pixelUnpackSkipImages = param;
942 			break;
943 
944 		default:
945 			setError(GL_INVALID_ENUM);
946 	}
947 }
948 
949 tcu::ConstPixelBufferAccess ReferenceContext::getUnpack2DAccess (const tcu::TextureFormat& format, int width, int height, const void* data)
950 {
951 	int				pixelSize	= format.getPixelSize();
952 	int				rowLen		= m_pixelUnpackRowLength > 0 ? m_pixelUnpackRowLength : width;
953 	int				rowPitch	= deAlign32(rowLen*pixelSize, m_pixelUnpackAlignment);
954 	const deUint8*	ptr			= (const deUint8*)data + m_pixelUnpackSkipRows*rowPitch + m_pixelUnpackSkipPixels*pixelSize;
955 
956 	return tcu::ConstPixelBufferAccess(format, width, height, 1, rowPitch, 0, ptr);
957 }
958 
959 tcu::ConstPixelBufferAccess ReferenceContext::getUnpack3DAccess (const tcu::TextureFormat& format, int width, int height, int depth, const void* data)
960 {
961 	int				pixelSize	= format.getPixelSize();
962 	int				rowLen		= m_pixelUnpackRowLength	> 0 ? m_pixelUnpackRowLength	: width;
963 	int				imageHeight	= m_pixelUnpackImageHeight	> 0 ? m_pixelUnpackImageHeight	: height;
964 	int				rowPitch	= deAlign32(rowLen*pixelSize, m_pixelUnpackAlignment);
965 	int				slicePitch	= imageHeight*rowPitch;
966 	const deUint8*	ptr			= (const deUint8*)data + m_pixelUnpackSkipImages*slicePitch + m_pixelUnpackSkipRows*rowPitch + m_pixelUnpackSkipPixels*pixelSize;
967 
968 	return tcu::ConstPixelBufferAccess(format, width, height, depth, rowPitch, slicePitch, ptr);
969 }
970 
971 static tcu::TextureFormat mapInternalFormat (deUint32 internalFormat)
972 {
973 	switch (internalFormat)
974 	{
975 		case GL_ALPHA:				return TextureFormat(TextureFormat::A,		TextureFormat::UNORM_INT8);
976 		case GL_LUMINANCE:			return TextureFormat(TextureFormat::L,		TextureFormat::UNORM_INT8);
977 		case GL_LUMINANCE_ALPHA:	return TextureFormat(TextureFormat::LA,		TextureFormat::UNORM_INT8);
978 		case GL_RGB:				return TextureFormat(TextureFormat::RGB,	TextureFormat::UNORM_INT8);
979 		case GL_RGBA:				return TextureFormat(TextureFormat::RGBA,	TextureFormat::UNORM_INT8);
980 
981 		default:
982 			return glu::mapGLInternalFormat(internalFormat);
983 	}
984 }
985 
986 static void depthValueFloatClampCopy (const PixelBufferAccess& dst, const ConstPixelBufferAccess& src)
987 {
988 	int width	= dst.getWidth();
989 	int height	= dst.getHeight();
990 	int depth	= dst.getDepth();
991 
992 	DE_ASSERT(src.getWidth() == width && src.getHeight() == height && src.getDepth() == depth);
993 
994 	// clamping copy
995 
996 	if (src.getFormat().order == tcu::TextureFormat::DS && dst.getFormat().order == tcu::TextureFormat::DS)
997 	{
998 		// copy only depth and stencil
999 		for (int z = 0; z < depth; z++)
1000 		for (int y = 0; y < height; y++)
1001 		for (int x = 0; x < width; x++)
1002 		{
1003 			dst.setPixDepth(de::clamp(src.getPixDepth(x, y, z), 0.0f, 1.0f), x, y, z);
1004 			dst.setPixStencil(src.getPixStencil(x, y, z), x, y, z);
1005 		}
1006 	}
1007 	else
1008 	{
1009 		// copy only depth
1010 		for (int z = 0; z < depth; z++)
1011 		for (int y = 0; y < height; y++)
1012 		for (int x = 0; x < width; x++)
1013 			dst.setPixDepth(de::clamp(src.getPixDepth(x, y, z), 0.0f, 1.0f), x, y, z);
1014 	}
1015 }
1016 
1017 void ReferenceContext::texImage1D (deUint32 target, int level, deUint32 internalFormat, int width, int border, deUint32 format, deUint32 type, const void* data)
1018 {
1019 	texImage2D(target, level, internalFormat, width, 1, border, format, type, data);
1020 }
1021 
1022 void ReferenceContext::texImage2D (deUint32 target, int level, deUint32 internalFormat, int width, int height, int border, deUint32 format, deUint32 type, const void* data)
1023 {
1024 	texImage3D(target, level, internalFormat, width, height, 1, border, format, type, data);
1025 }
1026 
1027 static void clearToTextureInitialValue (PixelBufferAccess access)
1028 {
1029 	const bool hasDepth		= access.getFormat().order == tcu::TextureFormat::D || access.getFormat().order == tcu::TextureFormat::DS;
1030 	const bool hasStencil	= access.getFormat().order == tcu::TextureFormat::S || access.getFormat().order == tcu::TextureFormat::DS;
1031 	const bool hasColor		= !hasDepth && !hasStencil;
1032 
1033 	if (hasDepth)
1034 		tcu::clearDepth(access, 0.0f);
1035 	if (hasStencil)
1036 		tcu::clearStencil(access, 0u);
1037 	if (hasColor)
1038 		tcu::clear(access, Vec4(0.0f, 0.0f, 0.0f, 1.0f));
1039 }
1040 
1041 void ReferenceContext::texImage3D (deUint32 target, int level, deUint32 internalFormat, int width, int height, int depth, int border, deUint32 format, deUint32 type, const void* data)
1042 {
1043 	TextureUnit&		unit					= m_textureUnits[m_activeTexture];
1044 	const void*			unpackPtr				= getPixelUnpackPtr(data);
1045 	const bool			isDstFloatDepthFormat	= (internalFormat == GL_DEPTH_COMPONENT32F || internalFormat == GL_DEPTH32F_STENCIL8); // depth components are limited to [0,1] range
1046 	TextureFormat		storageFmt;
1047 	TextureFormat		transferFmt;
1048 
1049 	RC_IF_ERROR(border != 0, GL_INVALID_VALUE, RC_RET_VOID);
1050 	RC_IF_ERROR(width < 0 || height < 0 || depth < 0 || level < 0, GL_INVALID_VALUE, RC_RET_VOID);
1051 
1052 	// Map storage format.
1053 	storageFmt = mapInternalFormat(internalFormat);
1054 	RC_IF_ERROR(storageFmt.order	== TextureFormat::CHANNELORDER_LAST ||
1055 				storageFmt.type		== TextureFormat::CHANNELTYPE_LAST, GL_INVALID_ENUM, RC_RET_VOID);
1056 
1057 	// Map transfer format.
1058 	transferFmt = glu::mapGLTransferFormat(format, type);
1059 	RC_IF_ERROR(transferFmt.order	== TextureFormat::CHANNELORDER_LAST ||
1060 				transferFmt.type	== TextureFormat::CHANNELTYPE_LAST, GL_INVALID_ENUM, RC_RET_VOID);
1061 
1062 	if (target == GL_TEXTURE_1D && glu::isContextTypeGLCore(m_limits.contextType))
1063 	{
1064 		// Validate size and level.
1065 		RC_IF_ERROR(width > m_limits.maxTexture2DSize || height != 1 || depth != 1, GL_INVALID_VALUE, RC_RET_VOID);
1066 		RC_IF_ERROR(level > deLog2Floor32(m_limits.maxTexture2DSize), GL_INVALID_VALUE, RC_RET_VOID);
1067 
1068 		Texture1D* texture = unit.tex1DBinding ? unit.tex1DBinding : &unit.default1DTex;
1069 
1070 		if (texture->isImmutable())
1071 		{
1072 			RC_IF_ERROR(!texture->hasLevel(level), GL_INVALID_OPERATION, RC_RET_VOID);
1073 
1074 			ConstPixelBufferAccess dst(texture->getLevel(level));
1075 			RC_IF_ERROR(storageFmt	!= dst.getFormat()	||
1076 						width		!= dst.getWidth(), GL_INVALID_OPERATION, RC_RET_VOID);
1077 		}
1078 		else
1079 			texture->allocLevel(level, storageFmt, width);
1080 
1081 		if (unpackPtr)
1082 		{
1083 			ConstPixelBufferAccess	src		= getUnpack2DAccess(transferFmt, width, 1, unpackPtr);
1084 			PixelBufferAccess		dst		(texture->getLevel(level));
1085 
1086 			if (isDstFloatDepthFormat)
1087 				depthValueFloatClampCopy(dst, src);
1088 			else
1089 				tcu::copy(dst, src);
1090 		}
1091 		else
1092 		{
1093 			// No data supplied, clear to initial
1094 			clearToTextureInitialValue(texture->getLevel(level));
1095 		}
1096 	}
1097 	else if (target == GL_TEXTURE_2D)
1098 	{
1099 		// Validate size and level.
1100 		RC_IF_ERROR(width > m_limits.maxTexture2DSize || height > m_limits.maxTexture2DSize || depth != 1, GL_INVALID_VALUE, RC_RET_VOID);
1101 		RC_IF_ERROR(level > deLog2Floor32(m_limits.maxTexture2DSize), GL_INVALID_VALUE, RC_RET_VOID);
1102 
1103 		Texture2D* texture = unit.tex2DBinding ? unit.tex2DBinding : &unit.default2DTex;
1104 
isImmutable()1105 		if (texture->isImmutable())
1106 		{
1107 			RC_IF_ERROR(!texture->hasLevel(level), GL_INVALID_OPERATION, RC_RET_VOID);
1108 
1109 			ConstPixelBufferAccess dst(texture->getLevel(level));
1110 			RC_IF_ERROR(storageFmt	!= dst.getFormat()	||
1111 						width		!= dst.getWidth()	||
1112 						height		!= dst.getHeight(), GL_INVALID_OPERATION, RC_RET_VOID);
1113 		}
1114 		else
1115 			texture->allocLevel(level, storageFmt, width, height);
1116 
1117 		if (unpackPtr)
1118 		{
1119 			ConstPixelBufferAccess	src		= getUnpack2DAccess(transferFmt, width, height, unpackPtr);
1120 			PixelBufferAccess		dst		(texture->getLevel(level));
1121 
1122 			if (isDstFloatDepthFormat)
1123 				depthValueFloatClampCopy(dst, src);
1124 			else
1125 				tcu::copy(dst, src);
1126 		}
1127 		else
1128 		{
1129 			// No data supplied, clear to initial
1130 			clearToTextureInitialValue(texture->getLevel(level));
1131 		}
1132 	}
1133 	else if (target == GL_TEXTURE_CUBE_MAP_NEGATIVE_X ||
1134 			 target == GL_TEXTURE_CUBE_MAP_POSITIVE_X ||
1135 			 target == GL_TEXTURE_CUBE_MAP_NEGATIVE_Y ||
1136 			 target == GL_TEXTURE_CUBE_MAP_POSITIVE_Y ||
1137 			 target == GL_TEXTURE_CUBE_MAP_NEGATIVE_Z ||
1138 			 target == GL_TEXTURE_CUBE_MAP_POSITIVE_Z)
1139 	{
1140 		// Validate size and level.
1141 		RC_IF_ERROR(width != height || width > m_limits.maxTextureCubeSize || depth != 1, GL_INVALID_VALUE, RC_RET_VOID);
1142 		RC_IF_ERROR(level > deLog2Floor32(m_limits.maxTextureCubeSize), GL_INVALID_VALUE, RC_RET_VOID);
1143 
1144 		TextureCube*	texture	= unit.texCubeBinding ? unit.texCubeBinding : &unit.defaultCubeTex;
1145 		tcu::CubeFace	face	= mapGLCubeFace(target);
1146 
1147 		if (texture->isImmutable())
1148 		{
1149 			RC_IF_ERROR(!texture->hasFace(level, face), GL_INVALID_OPERATION, RC_RET_VOID);
1150 
1151 			ConstPixelBufferAccess dst(texture->getFace(level, face));
1152 			RC_IF_ERROR(storageFmt	!= dst.getFormat()	||
1153 						width		!= dst.getWidth()	||
1154 						height		!= dst.getHeight(), GL_INVALID_OPERATION, RC_RET_VOID);
1155 		}
1156 		else
1157 			texture->allocFace(level, face, storageFmt, width, height);
1158 
1159 		if (unpackPtr)
1160 		{
1161 			ConstPixelBufferAccess	src		= getUnpack2DAccess(transferFmt, width, height, unpackPtr);
1162 			PixelBufferAccess		dst		(texture->getFace(level, face));
1163 
1164 			if (isDstFloatDepthFormat)
1165 				depthValueFloatClampCopy(dst, src);
1166 			else
1167 				tcu::copy(dst, src);
1168 		}
1169 		else
1170 		{
1171 			// No data supplied, clear to initial
1172 			clearToTextureInitialValue(texture->getFace(level, face));
1173 		}
1174 	}
1175 	else if (target == GL_TEXTURE_2D_ARRAY)
1176 	{
1177 		// Validate size and level.
1178 		RC_IF_ERROR(width	> m_limits.maxTexture2DSize ||
1179 					height	> m_limits.maxTexture2DSize ||
1180 					depth	> m_limits.maxTexture2DArrayLayers, GL_INVALID_VALUE, RC_RET_VOID);
1181 		RC_IF_ERROR(level > deLog2Floor32(m_limits.maxTexture2DSize), GL_INVALID_VALUE, RC_RET_VOID);
1182 
1183 		Texture2DArray* texture = unit.tex2DArrayBinding ? unit.tex2DArrayBinding : &unit.default2DArrayTex;
1184 
1185 		if (texture->isImmutable())
1186 		{
1187 			RC_IF_ERROR(!texture->hasLevel(level), GL_INVALID_OPERATION, RC_RET_VOID);
1188 
1189 			ConstPixelBufferAccess dst(texture->getLevel(level));
1190 			RC_IF_ERROR(storageFmt	!= dst.getFormat()	||
1191 						width		!= dst.getWidth()	||
1192 						height		!= dst.getHeight()	||
1193 						depth		!= dst.getDepth(), GL_INVALID_OPERATION, RC_RET_VOID);
1194 		}
1195 		else
1196 			texture->allocLevel(level, storageFmt, width, height, depth);
1197 
1198 		if (unpackPtr)
1199 		{
1200 			ConstPixelBufferAccess	src		= getUnpack3DAccess(transferFmt, width, height, depth, unpackPtr);
1201 			PixelBufferAccess		dst		(texture->getLevel(level));
1202 
1203 			if (isDstFloatDepthFormat)
1204 				depthValueFloatClampCopy(dst, src);
1205 			else
1206 				tcu::copy(dst, src);
1207 		}
1208 		else
1209 		{
1210 			// No data supplied, clear to initial
1211 			clearToTextureInitialValue(texture->getLevel(level));
1212 		}
1213 	}
1214 	else if (target == GL_TEXTURE_3D)
1215 	{
1216 		// Validate size and level.
1217 		RC_IF_ERROR(width	> m_limits.maxTexture3DSize ||
1218 					height	> m_limits.maxTexture3DSize ||
1219 					depth	> m_limits.maxTexture3DSize, GL_INVALID_VALUE, RC_RET_VOID);
1220 		RC_IF_ERROR(level > deLog2Floor32(m_limits.maxTexture3DSize), GL_INVALID_VALUE, RC_RET_VOID);
1221 
1222 		Texture3D* texture = unit.tex3DBinding ? unit.tex3DBinding : &unit.default3DTex;
1223 
1224 		if (texture->isImmutable())
1225 		{
1226 			RC_IF_ERROR(!texture->hasLevel(level), GL_INVALID_OPERATION, RC_RET_VOID);
1227 
1228 			ConstPixelBufferAccess dst(texture->getLevel(level));
1229 			RC_IF_ERROR(storageFmt	!= dst.getFormat()	||
1230 						width		!= dst.getWidth()	||
1231 						height		!= dst.getHeight()	||
1232 						depth		!= dst.getDepth(), GL_INVALID_OPERATION, RC_RET_VOID);
1233 		}
1234 		else
1235 			texture->allocLevel(level, storageFmt, width, height, depth);
1236 
1237 		if (unpackPtr)
1238 		{
1239 			ConstPixelBufferAccess	src		= getUnpack3DAccess(transferFmt, width, height, depth, unpackPtr);
1240 			PixelBufferAccess		dst		(texture->getLevel(level));
1241 
1242 			if (isDstFloatDepthFormat)
1243 				depthValueFloatClampCopy(dst, src);
1244 			else
1245 				tcu::copy(dst, src);
1246 		}
1247 		else
1248 		{
1249 			// No data supplied, clear to initial
1250 			clearToTextureInitialValue(texture->getLevel(level));
1251 		}
1252 	}
1253 	else if (target == GL_TEXTURE_CUBE_MAP_ARRAY)
1254 	{
1255 		// Validate size and level.
1256 		RC_IF_ERROR(width		!= height						||
1257 					width		 > m_limits.maxTexture2DSize	||
1258 					depth % 6	!= 0							||
1259 					depth		 > m_limits.maxTexture2DArrayLayers, GL_INVALID_VALUE, RC_RET_VOID);
1260 		RC_IF_ERROR(level > deLog2Floor32(m_limits.maxTexture2DSize), GL_INVALID_VALUE, RC_RET_VOID);
1261 
1262 		TextureCubeArray* texture = unit.texCubeArrayBinding ? unit.texCubeArrayBinding : &unit.defaultCubeArrayTex;
1263 
1264 		if (texture->isImmutable())
1265 		{
1266 			RC_IF_ERROR(!texture->hasLevel(level), GL_INVALID_OPERATION, RC_RET_VOID);
1267 
1268 			ConstPixelBufferAccess dst(texture->getLevel(level));
1269 			RC_IF_ERROR(storageFmt	!= dst.getFormat()	||
1270 						width		!= dst.getWidth()	||
1271 						height		!= dst.getHeight()	||
1272 						depth		!= dst.getDepth(), GL_INVALID_OPERATION, RC_RET_VOID);
1273 		}
1274 		else
1275 			texture->allocLevel(level, storageFmt, width, height, depth);
1276 
1277 		if (unpackPtr)
1278 		{
1279 			ConstPixelBufferAccess	src		= getUnpack3DAccess(transferFmt, width, height, depth, unpackPtr);
1280 			PixelBufferAccess		dst		(texture->getLevel(level));
1281 
1282 			if (isDstFloatDepthFormat)
1283 				depthValueFloatClampCopy(dst, src);
1284 			else
1285 				tcu::copy(dst, src);
1286 		}
1287 		else
1288 		{
1289 			// No data supplied, clear to initial
1290 			clearToTextureInitialValue(texture->getLevel(level));
1291 		}
1292 	}
1293 	else
1294 		RC_ERROR_RET(GL_INVALID_ENUM, RC_RET_VOID);
1295 }
1296 
texSubImage1D(deUint32 target, int level, int xoffset, int width, deUint32 format, deUint32 type, const void* data)1297 void ReferenceContext::texSubImage1D (deUint32 target, int level, int xoffset, int width, deUint32 format, deUint32 type, const void* data)
1298 {
1299 	texSubImage2D(target, level, xoffset, 0, width, 1, format, type, data);
1300 }
1301 
texSubImage2D(deUint32 target, int level, int xoffset, int yoffset, int width, int height, deUint32 format, deUint32 type, const void* data)1302 void ReferenceContext::texSubImage2D (deUint32 target, int level, int xoffset, int yoffset, int width, int height, deUint32 format, deUint32 type, const void* data)
1303 {
1304 	texSubImage3D(target, level, xoffset, yoffset, 0, width, height, 1, format, type, data);
1305 }
1306 
texSubImage3D(deUint32 target, int level, int xoffset, int yoffset, int zoffset, int width, int height, int depth, deUint32 format, deUint32 type, const void* data)1307 void ReferenceContext::texSubImage3D (deUint32 target, int level, int xoffset, int yoffset, int zoffset, int width, int height, int depth, deUint32 format, deUint32 type, const void* data)
1308 {
1309 	TextureUnit& unit = m_textureUnits[m_activeTexture];
1310 
1311 	RC_IF_ERROR(xoffset < 0 || yoffset < 0 || zoffset < 0,	GL_INVALID_VALUE, RC_RET_VOID);
1312 	RC_IF_ERROR(width < 0 || height < 0 || depth < 0,		GL_INVALID_VALUE, RC_RET_VOID);
1313 
1314 	TextureFormat transferFmt = glu::mapGLTransferFormat(format, type);
1315 	RC_IF_ERROR(transferFmt.order	== TextureFormat::CHANNELORDER_LAST ||
1316 				transferFmt.type	== TextureFormat::CHANNELTYPE_LAST, GL_INVALID_ENUM, RC_RET_VOID);
1317 
1318 	ConstPixelBufferAccess src = getUnpack3DAccess(transferFmt, width, height, depth, getPixelUnpackPtr(data));
1319 
1320 	if (target == GL_TEXTURE_1D && glu::isContextTypeGLCore(m_limits.contextType))
1321 	{
1322 		Texture1D& texture = unit.tex1DBinding ? *unit.tex1DBinding : unit.default1DTex;
1323 
1324 		RC_IF_ERROR(!texture.hasLevel(level), GL_INVALID_VALUE, RC_RET_VOID);
1325 
1326 		PixelBufferAccess dst = texture.getLevel(level);
1327 
1328 		RC_IF_ERROR(xoffset + width		> dst.getWidth()	||
1329 					yoffset + height	> dst.getHeight()	||
1330 					zoffset + depth		> dst.getDepth(),
1331 					GL_INVALID_VALUE, RC_RET_VOID);
1332 
1333 		// depth components are limited to [0,1] range
1334 		if (dst.getFormat().order == tcu::TextureFormat::D || dst.getFormat().order == tcu::TextureFormat::DS)
1335 			depthValueFloatClampCopy(tcu::getSubregion(dst, xoffset, yoffset, zoffset, width, height, depth), src);
1336 		else
1337 			tcu::copy(tcu::getSubregion(dst, xoffset, yoffset, zoffset, width, height, depth), src);
1338 	}
1339 	else if (target == GL_TEXTURE_2D)
1340 	{
1341 		Texture2D& texture = unit.tex2DBinding ? *unit.tex2DBinding : unit.default2DTex;
1342 
1343 		RC_IF_ERROR(!texture.hasLevel(level), GL_INVALID_VALUE, RC_RET_VOID);
1344 
1345 		PixelBufferAccess dst = texture.getLevel(level);
1346 
1347 		RC_IF_ERROR(xoffset + width		> dst.getWidth()	||
1348 					yoffset + height	> dst.getHeight()	||
1349 					zoffset + depth		> dst.getDepth(),
1350 					GL_INVALID_VALUE, RC_RET_VOID);
1351 
1352 		// depth components are limited to [0,1] range
1353 		if (dst.getFormat().order == tcu::TextureFormat::D || dst.getFormat().order == tcu::TextureFormat::DS)
1354 			depthValueFloatClampCopy(tcu::getSubregion(dst, xoffset, yoffset, zoffset, width, height, depth), src);
1355 		else
1356 			tcu::copy(tcu::getSubregion(dst, xoffset, yoffset, zoffset, width, height, depth), src);
1357 	}
1358 	else if (target == GL_TEXTURE_CUBE_MAP_NEGATIVE_X ||
1359 			 target == GL_TEXTURE_CUBE_MAP_POSITIVE_X ||
1360 			 target == GL_TEXTURE_CUBE_MAP_NEGATIVE_Y ||
1361 			 target == GL_TEXTURE_CUBE_MAP_POSITIVE_Y ||
1362 			 target == GL_TEXTURE_CUBE_MAP_NEGATIVE_Z ||
1363 			 target == GL_TEXTURE_CUBE_MAP_POSITIVE_Z)
1364 	{
1365 		TextureCube&	texture		= unit.texCubeBinding ? *unit.texCubeBinding : unit.defaultCubeTex;
1366 		tcu::CubeFace	face		= mapGLCubeFace(target);
1367 
1368 		RC_IF_ERROR(!texture.hasFace(level, face), GL_INVALID_VALUE, RC_RET_VOID);
1369 
1370 		PixelBufferAccess dst = texture.getFace(level, face);
1371 
1372 		RC_IF_ERROR(xoffset + width		> dst.getWidth()	||
1373 					yoffset + height	> dst.getHeight()	||
1374 					zoffset + depth		> dst.getDepth(),
1375 					GL_INVALID_VALUE, RC_RET_VOID);
1376 
1377 		// depth components are limited to [0,1] range
1378 		if (dst.getFormat().order == tcu::TextureFormat::D || dst.getFormat().order == tcu::TextureFormat::DS)
1379 			depthValueFloatClampCopy(tcu::getSubregion(dst, xoffset, yoffset, zoffset, width, height, depth), src);
1380 		else
1381 			tcu::copy(tcu::getSubregion(dst, xoffset, yoffset, zoffset, width, height, depth), src);
1382 	}
1383 	else if (target == GL_TEXTURE_3D)
1384 	{
1385 		Texture3D& texture = unit.tex3DBinding ? *unit.tex3DBinding : unit.default3DTex;
1386 
1387 		RC_IF_ERROR(!texture.hasLevel(level), GL_INVALID_VALUE, RC_RET_VOID);
1388 
1389 		PixelBufferAccess dst = texture.getLevel(level);
1390 
1391 		RC_IF_ERROR(xoffset + width		> dst.getWidth()	||
1392 					yoffset + height	> dst.getHeight()	||
1393 					zoffset + depth		> dst.getDepth(),
1394 					GL_INVALID_VALUE, RC_RET_VOID);
1395 
1396 		// depth components are limited to [0,1] range
1397 		if (dst.getFormat().order == tcu::TextureFormat::D || dst.getFormat().order == tcu::TextureFormat::DS)
1398 			depthValueFloatClampCopy(tcu::getSubregion(dst, xoffset, yoffset, zoffset, width, height, depth), src);
1399 		else
1400 			tcu::copy(tcu::getSubregion(dst, xoffset, yoffset, zoffset, width, height, depth), src);
1401 	}
1402 	else if (target == GL_TEXTURE_2D_ARRAY)
1403 	{
1404 		Texture2DArray& texture = unit.tex2DArrayBinding ? *unit.tex2DArrayBinding : unit.default2DArrayTex;
1405 
1406 		RC_IF_ERROR(!texture.hasLevel(level), GL_INVALID_VALUE, RC_RET_VOID);
1407 
1408 		PixelBufferAccess dst = texture.getLevel(level);
1409 
1410 		RC_IF_ERROR(xoffset + width		> dst.getWidth()	||
1411 					yoffset + height	> dst.getHeight()	||
1412 					zoffset + depth		> dst.getDepth(),
1413 					GL_INVALID_VALUE, RC_RET_VOID);
1414 
1415 		// depth components are limited to [0,1] range
1416 		if (dst.getFormat().order == tcu::TextureFormat::D || dst.getFormat().order == tcu::TextureFormat::DS)
1417 			depthValueFloatClampCopy(tcu::getSubregion(dst, xoffset, yoffset, zoffset, width, height, depth), src);
1418 		else
1419 			tcu::copy(tcu::getSubregion(dst, xoffset, yoffset, zoffset, width, height, depth), src);
1420 	}
1421 	else if (target == GL_TEXTURE_CUBE_MAP_ARRAY)
1422 	{
1423 		TextureCubeArray& texture = unit.texCubeArrayBinding ? *unit.texCubeArrayBinding : unit.defaultCubeArrayTex;
1424 
1425 		RC_IF_ERROR(!texture.hasLevel(level), GL_INVALID_VALUE, RC_RET_VOID);
1426 
1427 		PixelBufferAccess dst = texture.getLevel(level);
1428 
1429 		RC_IF_ERROR(xoffset + width		> dst.getWidth()	||
1430 					yoffset + height	> dst.getHeight()	||
1431 					zoffset + depth		> dst.getDepth(),
1432 					GL_INVALID_VALUE, RC_RET_VOID);
1433 
1434 		// depth components are limited to [0,1] range
1435 		if (dst.getFormat().order == tcu::TextureFormat::D || dst.getFormat().order == tcu::TextureFormat::DS)
1436 			depthValueFloatClampCopy(tcu::getSubregion(dst, xoffset, yoffset, zoffset, width, height, depth), src);
1437 		else
1438 			tcu::copy(tcu::getSubregion(dst, xoffset, yoffset, zoffset, width, height, depth), src);
1439 	}
1440 	else
1441 		RC_ERROR_RET(GL_INVALID_ENUM, RC_RET_VOID);
1442 }
1443 
copyTexImage1D(deUint32 target, int level, deUint32 internalFormat, int x, int y, int width, int border)1444 void ReferenceContext::copyTexImage1D (deUint32 target, int level, deUint32 internalFormat, int x, int y, int width, int border)
1445 {
1446 	TextureUnit&							unit		= m_textureUnits[m_activeTexture];
1447 	TextureFormat							storageFmt;
1448 	rr::MultisampleConstPixelBufferAccess	src			= getReadColorbuffer();
1449 
1450 	RC_IF_ERROR(border != 0, GL_INVALID_VALUE, RC_RET_VOID);
1451 	RC_IF_ERROR(width < 0 || level < 0, GL_INVALID_VALUE, RC_RET_VOID);
1452 	RC_IF_ERROR(isEmpty(src), GL_INVALID_OPERATION, RC_RET_VOID);
1453 
1454 	// Map storage format.
1455 	storageFmt = mapInternalFormat(internalFormat);
1456 	RC_IF_ERROR(storageFmt.order	== TextureFormat::CHANNELORDER_LAST ||
1457 				storageFmt.type		== TextureFormat::CHANNELTYPE_LAST, GL_INVALID_ENUM, RC_RET_VOID);
1458 
1459 	if (target == GL_TEXTURE_1D)
1460 	{
1461 		// Validate size and level.
1462 		RC_IF_ERROR(width > m_limits.maxTexture2DSize, GL_INVALID_VALUE, RC_RET_VOID);
1463 		RC_IF_ERROR(level > deLog2Floor32(m_limits.maxTexture2DSize), GL_INVALID_VALUE, RC_RET_VOID);
1464 
1465 		Texture1D* texture = unit.tex1DBinding ? unit.tex1DBinding : &unit.default1DTex;
1466 
1467 		if (texture->isImmutable())
1468 		{
1469 			RC_IF_ERROR(!texture->hasLevel(level), GL_INVALID_OPERATION, RC_RET_VOID);
1470 
1471 			ConstPixelBufferAccess dst(texture->getLevel(level));
1472 			RC_IF_ERROR(storageFmt	!= dst.getFormat()	||
1473 						width		!= dst.getWidth(), GL_INVALID_OPERATION, RC_RET_VOID);
1474 		}
1475 		else
1476 			texture->allocLevel(level, storageFmt, width);
1477 
1478 		// Copy from current framebuffer.
1479 		PixelBufferAccess dst = texture->getLevel(level);
1480 		for (int xo = 0; xo < width; xo++)
1481 		{
1482 			if (!de::inBounds(x+xo, 0, src.raw().getHeight()))
1483 				continue; // Undefined pixel.
1484 
1485 			dst.setPixel(rr::resolveMultisamplePixel(src, x+xo, y), xo, 0);
1486 		}
1487 	}
1488 	else
1489 		RC_ERROR_RET(GL_INVALID_ENUM, RC_RET_VOID);
1490 }
1491 
1492 void ReferenceContext::copyTexImage2D (deUint32 target, int level, deUint32 internalFormat, int x, int y, int width, int height, int border)
1493 {
1494 	TextureUnit&							unit		= m_textureUnits[m_activeTexture];
1495 	TextureFormat							storageFmt;
1496 	rr::MultisampleConstPixelBufferAccess	src			= getReadColorbuffer();
1497 
1498 	RC_IF_ERROR(border != 0, GL_INVALID_VALUE, RC_RET_VOID);
1499 	RC_IF_ERROR(width < 0 || height < 0 || level < 0, GL_INVALID_VALUE, RC_RET_VOID);
1500 	RC_IF_ERROR(isEmpty(src), GL_INVALID_OPERATION, RC_RET_VOID);
1501 
1502 	// Map storage format.
1503 	storageFmt = mapInternalFormat(internalFormat);
1504 	RC_IF_ERROR(storageFmt.order	== TextureFormat::CHANNELORDER_LAST ||
1505 				storageFmt.type		== TextureFormat::CHANNELTYPE_LAST, GL_INVALID_ENUM, RC_RET_VOID);
1506 
1507 	if (target == GL_TEXTURE_2D)
1508 	{
1509 		// Validate size and level.
1510 		RC_IF_ERROR(width > m_limits.maxTexture2DSize || height > m_limits.maxTexture2DSize, GL_INVALID_VALUE, RC_RET_VOID);
1511 		RC_IF_ERROR(level > deLog2Floor32(m_limits.maxTexture2DSize), GL_INVALID_VALUE, RC_RET_VOID);
1512 
1513 		Texture2D* texture = unit.tex2DBinding ? unit.tex2DBinding : &unit.default2DTex;
1514 
1515 		if (texture->isImmutable())
1516 		{
1517 			RC_IF_ERROR(!texture->hasLevel(level), GL_INVALID_OPERATION, RC_RET_VOID);
1518 
1519 			ConstPixelBufferAccess dst(texture->getLevel(level));
1520 			RC_IF_ERROR(storageFmt	!= dst.getFormat()	||
1521 						width		!= dst.getWidth()	||
1522 						height		!= dst.getHeight(), GL_INVALID_OPERATION, RC_RET_VOID);
1523 		}
1524 		else
1525 			texture->allocLevel(level, storageFmt, width, height);
1526 
1527 		// Copy from current framebuffer.
1528 		PixelBufferAccess dst = texture->getLevel(level);
1529 		for (int yo = 0; yo < height; yo++)
1530 		for (int xo = 0; xo < width; xo++)
1531 		{
1532 			if (!de::inBounds(x+xo, 0, src.raw().getHeight()) || !de::inBounds(y+yo, 0, src.raw().getDepth()))
1533 				continue; // Undefined pixel.
1534 
1535 			dst.setPixel(rr::resolveMultisamplePixel(src, x+xo, y+yo), xo, yo);
1536 		}
1537 	}
1538 	else if (target == GL_TEXTURE_CUBE_MAP_NEGATIVE_X ||
1539 			 target == GL_TEXTURE_CUBE_MAP_POSITIVE_X ||
1540 			 target == GL_TEXTURE_CUBE_MAP_NEGATIVE_Y ||
1541 			 target == GL_TEXTURE_CUBE_MAP_POSITIVE_Y ||
1542 			 target == GL_TEXTURE_CUBE_MAP_NEGATIVE_Z ||
1543 			 target == GL_TEXTURE_CUBE_MAP_POSITIVE_Z)
1544 	{
1545 		// Validate size and level.
1546 		RC_IF_ERROR(width != height || width > m_limits.maxTextureCubeSize, GL_INVALID_VALUE, RC_RET_VOID);
1547 		RC_IF_ERROR(level > deLog2Floor32(m_limits.maxTextureCubeSize), GL_INVALID_VALUE, RC_RET_VOID);
1548 
1549 		TextureCube*	texture	= unit.texCubeBinding ? unit.texCubeBinding : &unit.defaultCubeTex;
1550 		tcu::CubeFace	face	= mapGLCubeFace(target);
1551 
1552 		if (texture->isImmutable())
1553 		{
1554 			RC_IF_ERROR(!texture->hasFace(level, face), GL_INVALID_OPERATION, RC_RET_VOID);
1555 
1556 			ConstPixelBufferAccess dst(texture->getFace(level, face));
1557 			RC_IF_ERROR(storageFmt	!= dst.getFormat()	||
1558 						width		!= dst.getWidth()	||
1559 						height		!= dst.getHeight(), GL_INVALID_OPERATION, RC_RET_VOID);
1560 		}
1561 		else
1562 			texture->allocFace(level, face, storageFmt, width, height);
1563 
1564 		// Copy from current framebuffer.
1565 		PixelBufferAccess dst = texture->getFace(level, face);
1566 		for (int yo = 0; yo < height; yo++)
1567 		for (int xo = 0; xo < width; xo++)
1568 		{
1569 			if (!de::inBounds(x+xo, 0, src.raw().getHeight()) || !de::inBounds(y+yo, 0, src.raw().getDepth()))
1570 				continue; // Undefined pixel.
1571 
1572 			dst.setPixel(rr::resolveMultisamplePixel(src, x+xo, y+yo), xo, yo);
1573 		}
1574 	}
1575 	else
1576 		RC_ERROR_RET(GL_INVALID_ENUM, RC_RET_VOID);
1577 }
1578 
1579 void ReferenceContext::copyTexSubImage1D (deUint32 target, int level, int xoffset, int x, int y, int width)
1580 {
1581 	TextureUnit&							unit	= m_textureUnits[m_activeTexture];
1582 	rr::MultisampleConstPixelBufferAccess	src		= getReadColorbuffer();
1583 
1584 	RC_IF_ERROR(xoffset < 0,	GL_INVALID_VALUE,		RC_RET_VOID);
1585 	RC_IF_ERROR(width < 0,		GL_INVALID_VALUE,		RC_RET_VOID);
1586 	RC_IF_ERROR(isEmpty(src),	GL_INVALID_OPERATION,	RC_RET_VOID);
1587 
1588 	if (target == GL_TEXTURE_1D)
1589 	{
1590 		Texture1D& texture = unit.tex1DBinding ? *unit.tex1DBinding : unit.default1DTex;
1591 
1592 		RC_IF_ERROR(!texture.hasLevel(level), GL_INVALID_VALUE, RC_RET_VOID);
1593 
1594 		PixelBufferAccess dst = texture.getLevel(level);
1595 
1596 		RC_IF_ERROR(xoffset + width > dst.getWidth(), GL_INVALID_VALUE, RC_RET_VOID);
1597 
1598 		for (int xo = 0; xo < width; xo++)
1599 		{
1600 			if (!de::inBounds(x+xo, 0, src.raw().getHeight()))
1601 				continue;
1602 
1603 			dst.setPixel(rr::resolveMultisamplePixel(src, x+xo, y), xo+xoffset, 0);
1604 		}
1605 	}
1606 	else
1607 		RC_ERROR_RET(GL_INVALID_ENUM, RC_RET_VOID);
1608 }
1609 
1610 void ReferenceContext::copyTexSubImage2D (deUint32 target, int level, int xoffset, int yoffset, int x, int y, int width, int height)
1611 {
1612 	TextureUnit&							unit	= m_textureUnits[m_activeTexture];
1613 	rr::MultisampleConstPixelBufferAccess	src		= getReadColorbuffer();
1614 
1615 	RC_IF_ERROR(xoffset < 0 || yoffset < 0,					GL_INVALID_VALUE, RC_RET_VOID);
1616 	RC_IF_ERROR(width < 0 || height < 0,					GL_INVALID_VALUE, RC_RET_VOID);
1617 	RC_IF_ERROR(isEmpty(src),								GL_INVALID_OPERATION, RC_RET_VOID);
1618 
1619 	if (target == GL_TEXTURE_2D)
1620 	{
1621 		Texture2D& texture = unit.tex2DBinding ? *unit.tex2DBinding : unit.default2DTex;
1622 
1623 		RC_IF_ERROR(!texture.hasLevel(level), GL_INVALID_VALUE, RC_RET_VOID);
1624 
1625 		PixelBufferAccess dst = texture.getLevel(level);
1626 
1627 		RC_IF_ERROR(xoffset + width		> dst.getWidth() ||
1628 					yoffset + height	> dst.getHeight(),
1629 					GL_INVALID_VALUE, RC_RET_VOID);
1630 
1631 		for (int yo = 0; yo < height; yo++)
1632 		for (int xo = 0; xo < width; xo++)
1633 		{
1634 			if (!de::inBounds(x+xo, 0, src.raw().getHeight()) || !de::inBounds(y+yo, 0, src.raw().getDepth()))
1635 				continue;
1636 
1637 			dst.setPixel(rr::resolveMultisamplePixel(src, x+xo, y+yo), xo+xoffset, yo+yoffset);
1638 		}
1639 	}
1640 	else if (target == GL_TEXTURE_CUBE_MAP_NEGATIVE_X ||
1641 			 target == GL_TEXTURE_CUBE_MAP_POSITIVE_X ||
1642 			 target == GL_TEXTURE_CUBE_MAP_NEGATIVE_Y ||
1643 			 target == GL_TEXTURE_CUBE_MAP_POSITIVE_Y ||
1644 			 target == GL_TEXTURE_CUBE_MAP_NEGATIVE_Z ||
1645 			 target == GL_TEXTURE_CUBE_MAP_POSITIVE_Z)
1646 	{
1647 		TextureCube&	texture		= unit.texCubeBinding ? *unit.texCubeBinding : unit.defaultCubeTex;
1648 		tcu::CubeFace	face		= mapGLCubeFace(target);
1649 
1650 		RC_IF_ERROR(!texture.hasFace(level, face), GL_INVALID_VALUE, RC_RET_VOID);
1651 
1652 		PixelBufferAccess dst = texture.getFace(level, face);
1653 
1654 		RC_IF_ERROR(xoffset + width		> dst.getWidth() ||
1655 					yoffset + height	> dst.getHeight(),
1656 					GL_INVALID_VALUE, RC_RET_VOID);
1657 
1658 		for (int yo = 0; yo < height; yo++)
1659 		for (int xo = 0; xo < width; xo++)
1660 		{
1661 			if (!de::inBounds(x+xo, 0, src.raw().getHeight()) || !de::inBounds(y+yo, 0, src.raw().getDepth()))
1662 				continue;
1663 
1664 			dst.setPixel(rr::resolveMultisamplePixel(src, x+xo, y+yo), xo+xoffset, yo+yoffset);
1665 		}
1666 	}
1667 	else
1668 		RC_ERROR_RET(GL_INVALID_ENUM, RC_RET_VOID);
1669 }
1670 
1671 void ReferenceContext::copyTexSubImage3D (deUint32 target, int level, int xoffset, int yoffset, int zoffset, int x, int y, int width, int height)
1672 {
1673 	DE_UNREF(target && level && xoffset && yoffset && zoffset && x && y && width && height);
1674 	DE_ASSERT(false);
1675 }
1676 
1677 void ReferenceContext::texStorage2D (deUint32 target, int levels, deUint32 internalFormat, int width, int height)
1678 {
1679 	TextureUnit&		unit		= m_textureUnits[m_activeTexture];
1680 	TextureFormat		storageFmt;
1681 
1682 	RC_IF_ERROR(width <= 0 || height <= 0, GL_INVALID_VALUE, RC_RET_VOID);
1683 	RC_IF_ERROR(!de::inRange(levels, 1, (int)deLog2Floor32(de::max(width, height))+1), GL_INVALID_VALUE, RC_RET_VOID);
1684 
1685 	// Map storage format.
1686 	storageFmt = mapInternalFormat(internalFormat);
1687 	RC_IF_ERROR(storageFmt.order	== TextureFormat::CHANNELORDER_LAST ||
1688 				storageFmt.type		== TextureFormat::CHANNELTYPE_LAST, GL_INVALID_ENUM, RC_RET_VOID);
1689 
1690 	if (target == GL_TEXTURE_2D)
1691 	{
1692 		Texture2D& texture = unit.tex2DBinding ? *unit.tex2DBinding : unit.default2DTex;
1693 
1694 		RC_IF_ERROR(width > m_limits.maxTexture2DSize || height >= m_limits.maxTexture2DSize, GL_INVALID_VALUE, RC_RET_VOID);
1695 		RC_IF_ERROR(texture.isImmutable(), GL_INVALID_OPERATION, RC_RET_VOID);
1696 
1697 		texture.clearLevels();
1698 		texture.setImmutable();
1699 
1700 		for (int level = 0; level < levels; level++)
1701 		{
1702 			int levelW = de::max(1, width >> level);
1703 			int levelH = de::max(1, height >> level);
1704 
1705 			texture.allocLevel(level, storageFmt, levelW, levelH);
1706 		}
1707 	}
1708 	else if (target == GL_TEXTURE_CUBE_MAP)
1709 	{
1710 		TextureCube& texture = unit.texCubeBinding ? *unit.texCubeBinding : unit.defaultCubeTex;
1711 
1712 		RC_IF_ERROR(width > m_limits.maxTextureCubeSize || height > m_limits.maxTextureCubeSize, GL_INVALID_VALUE, RC_RET_VOID);
1713 		RC_IF_ERROR(texture.isImmutable(), GL_INVALID_OPERATION, RC_RET_VOID);
1714 
1715 		texture.clearLevels();
1716 		texture.setImmutable();
1717 
1718 		for (int level = 0; level < levels; level++)
1719 		{
1720 			int levelW = de::max(1, width >> level);
1721 			int levelH = de::max(1, height >> level);
1722 
1723 			for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
1724 				texture.allocFace(level, (tcu::CubeFace)face, storageFmt, levelW, levelH);
1725 		}
1726 	}
1727 	else
1728 		RC_ERROR_RET(GL_INVALID_ENUM, RC_RET_VOID);
1729 }
1730 
1731 void ReferenceContext::texStorage3D (deUint32 target, int levels, deUint32 internalFormat, int width, int height, int depth)
1732 {
1733 	TextureUnit&		unit		= m_textureUnits[m_activeTexture];
1734 	TextureFormat		storageFmt;
1735 
1736 	RC_IF_ERROR(width <= 0 || height <= 0, GL_INVALID_VALUE, RC_RET_VOID);
1737 	RC_IF_ERROR(!de::inRange(levels, 1, (int)deLog2Floor32(de::max(width, height))+1), GL_INVALID_VALUE, RC_RET_VOID);
1738 
1739 	// Map storage format.
1740 	storageFmt = mapInternalFormat(internalFormat);
1741 	RC_IF_ERROR(storageFmt.order	== TextureFormat::CHANNELORDER_LAST ||
1742 				storageFmt.type		== TextureFormat::CHANNELTYPE_LAST, GL_INVALID_ENUM, RC_RET_VOID);
1743 
1744 	if (target == GL_TEXTURE_2D_ARRAY)
1745 	{
1746 		Texture2DArray& texture = unit.tex2DArrayBinding ? *unit.tex2DArrayBinding : unit.default2DArrayTex;
1747 
1748 		RC_IF_ERROR(width	>	m_limits.maxTexture2DSize	||
1749 					height	>=	m_limits.maxTexture2DSize	||
1750 					depth	>=	m_limits.maxTexture2DArrayLayers, GL_INVALID_VALUE, RC_RET_VOID);
1751 		RC_IF_ERROR(texture.isImmutable(), GL_INVALID_OPERATION, RC_RET_VOID);
1752 
1753 		texture.clearLevels();
1754 		texture.setImmutable();
1755 
1756 		for (int level = 0; level < levels; level++)
1757 		{
1758 			int levelW = de::max(1, width >> level);
1759 			int levelH = de::max(1, height >> level);
1760 
1761 			texture.allocLevel(level, storageFmt, levelW, levelH, depth);
1762 		}
1763 	}
1764 	else if (target == GL_TEXTURE_3D)
1765 	{
1766 		Texture3D& texture = unit.tex3DBinding ? *unit.tex3DBinding : unit.default3DTex;
1767 
1768 		RC_IF_ERROR(width	> m_limits.maxTexture3DSize	||
1769 					height	> m_limits.maxTexture3DSize	||
1770 					depth	> m_limits.maxTexture3DSize, GL_INVALID_VALUE, RC_RET_VOID);
1771 		RC_IF_ERROR(texture.isImmutable(), GL_INVALID_OPERATION, RC_RET_VOID);
1772 
1773 		texture.clearLevels();
1774 		texture.setImmutable();
1775 
1776 		for (int level = 0; level < levels; level++)
1777 		{
1778 			int levelW = de::max(1, width		>> level);
1779 			int levelH = de::max(1, height	>> level);
1780 			int levelD = de::max(1, depth		>> level);
1781 
1782 			texture.allocLevel(level, storageFmt, levelW, levelH, levelD);
1783 		}
1784 	}
1785 	else if (target == GL_TEXTURE_CUBE_MAP_ARRAY)
1786 	{
1787 		TextureCubeArray& texture = unit.texCubeArrayBinding ? *unit.texCubeArrayBinding : unit.defaultCubeArrayTex;
1788 
1789 		RC_IF_ERROR(width		!=	height								||
1790 					depth % 6	!= 0									||
1791 					width		>	m_limits.maxTexture2DSize			||
1792 					depth		>=	m_limits.maxTexture2DArrayLayers, GL_INVALID_VALUE, RC_RET_VOID);
1793 		RC_IF_ERROR(texture.isImmutable(), GL_INVALID_OPERATION, RC_RET_VOID);
1794 
1795 		texture.clearLevels();
1796 		texture.setImmutable();
1797 
1798 		for (int level = 0; level < levels; level++)
1799 		{
1800 			int levelW = de::max(1, width >> level);
1801 			int levelH = de::max(1, height >> level);
1802 
1803 			texture.allocLevel(level, storageFmt, levelW, levelH, depth);
1804 		}
1805 	}
1806 	else
1807 		RC_ERROR_RET(GL_INVALID_ENUM, RC_RET_VOID);
1808 }
1809 
1810 // \todo [2014-02-19 pyry] Duplicated with code in gluTextureUtil.hpp
1811 
1812 static inline tcu::Sampler::WrapMode mapGLWrapMode (int value)
1813 {
1814 	switch (value)
1815 	{
1816 		case GL_CLAMP_TO_EDGE:		return tcu::Sampler::CLAMP_TO_EDGE;
1817 		case GL_REPEAT:				return tcu::Sampler::REPEAT_GL;
1818 		case GL_MIRRORED_REPEAT:	return tcu::Sampler::MIRRORED_REPEAT_GL;
1819 		default:					return tcu::Sampler::WRAPMODE_LAST;
1820 	}
1821 }
1822 
1823 static inline tcu::Sampler::FilterMode mapGLFilterMode (int value)
1824 {
1825 	switch (value)
1826 	{
1827 		case GL_NEAREST:				return tcu::Sampler::NEAREST;
1828 		case GL_LINEAR:					return tcu::Sampler::LINEAR;
1829 		case GL_NEAREST_MIPMAP_NEAREST:	return tcu::Sampler::NEAREST_MIPMAP_NEAREST;
1830 		case GL_NEAREST_MIPMAP_LINEAR:	return tcu::Sampler::NEAREST_MIPMAP_LINEAR;
1831 		case GL_LINEAR_MIPMAP_NEAREST:	return tcu::Sampler::LINEAR_MIPMAP_NEAREST;
1832 		case GL_LINEAR_MIPMAP_LINEAR:	return tcu::Sampler::LINEAR_MIPMAP_LINEAR;
1833 		default:						return tcu::Sampler::FILTERMODE_LAST;
1834 	}
1835 }
1836 
1837 void ReferenceContext::texParameteri (deUint32 target, deUint32 pname, int value)
1838 {
1839 	TextureUnit&	unit		= m_textureUnits[m_activeTexture];
1840 	Texture*		texture		= DE_NULL;
1841 
1842 	switch (target)
1843 	{
1844 		case GL_TEXTURE_1D:				texture = unit.tex1DBinding			? unit.tex1DBinding			: &unit.default1DTex;			break;
1845 		case GL_TEXTURE_2D:				texture = unit.tex2DBinding			? unit.tex2DBinding			: &unit.default2DTex;			break;
1846 		case GL_TEXTURE_CUBE_MAP:		texture = unit.texCubeBinding		? unit.texCubeBinding		: &unit.defaultCubeTex;			break;
1847 		case GL_TEXTURE_2D_ARRAY:		texture = unit.tex2DArrayBinding	? unit.tex2DArrayBinding	: &unit.default2DArrayTex;		break;
1848 		case GL_TEXTURE_3D:				texture = unit.tex3DBinding			? unit.tex3DBinding			: &unit.default3DTex;			break;
1849 		case GL_TEXTURE_CUBE_MAP_ARRAY:	texture = unit.texCubeArrayBinding	? unit.texCubeArrayBinding	: &unit.defaultCubeArrayTex;	break;
1850 
1851 		default:					RC_ERROR_RET(GL_INVALID_ENUM, RC_RET_VOID);
1852 	}
1853 
1854 	switch (pname)
1855 	{
1856 		case GL_TEXTURE_WRAP_S:
1857 		{
1858 			tcu::Sampler::WrapMode wrapS = mapGLWrapMode(value);
1859 			RC_IF_ERROR(wrapS == tcu::Sampler::WRAPMODE_LAST, GL_INVALID_VALUE, RC_RET_VOID);
1860 			texture->getSampler().wrapS = wrapS;
1861 			break;
1862 		}
1863 
1864 		case GL_TEXTURE_WRAP_T:
1865 		{
1866 			tcu::Sampler::WrapMode wrapT = mapGLWrapMode(value);
1867 			RC_IF_ERROR(wrapT == tcu::Sampler::WRAPMODE_LAST, GL_INVALID_VALUE, RC_RET_VOID);
1868 			texture->getSampler().wrapT = wrapT;
1869 			break;
1870 		}
1871 
1872 		case GL_TEXTURE_WRAP_R:
1873 		{
1874 			tcu::Sampler::WrapMode wrapR = mapGLWrapMode(value);
1875 			RC_IF_ERROR(wrapR == tcu::Sampler::WRAPMODE_LAST, GL_INVALID_VALUE, RC_RET_VOID);
1876 			texture->getSampler().wrapR = wrapR;
1877 			break;
1878 		}
1879 
1880 		case GL_TEXTURE_MIN_FILTER:
1881 		{
1882 			tcu::Sampler::FilterMode minMode = mapGLFilterMode(value);
1883 			RC_IF_ERROR(minMode == tcu::Sampler::FILTERMODE_LAST, GL_INVALID_VALUE, RC_RET_VOID);
1884 			texture->getSampler().minFilter = minMode;
1885 			break;
1886 		}
1887 
1888 		case GL_TEXTURE_MAG_FILTER:
1889 		{
1890 			tcu::Sampler::FilterMode magMode = mapGLFilterMode(value);
1891 			RC_IF_ERROR(magMode != tcu::Sampler::LINEAR && magMode != tcu::Sampler::NEAREST,
1892 						GL_INVALID_VALUE, RC_RET_VOID);
1893 			texture->getSampler().magFilter = magMode;
1894 			break;
1895 		}
1896 
1897 		case GL_TEXTURE_MAX_LEVEL:
1898 		{
1899 			RC_IF_ERROR(value < 0, GL_INVALID_VALUE, RC_RET_VOID);
1900 			texture->setMaxLevel(value);
1901 			break;
1902 		}
1903 
1904 		default:
1905 			RC_ERROR_RET(GL_INVALID_ENUM, RC_RET_VOID);
1906 	}
1907 }
1908 
1909 static inline Framebuffer::AttachmentPoint mapGLAttachmentPoint (deUint32 attachment)
1910 {
1911 	switch (attachment)
1912 	{
1913 		case GL_COLOR_ATTACHMENT0:	return Framebuffer::ATTACHMENTPOINT_COLOR0;
1914 		case GL_DEPTH_ATTACHMENT:	return Framebuffer::ATTACHMENTPOINT_DEPTH;
1915 		case GL_STENCIL_ATTACHMENT:	return Framebuffer::ATTACHMENTPOINT_STENCIL;
1916 		default:					return Framebuffer::ATTACHMENTPOINT_LAST;
1917 	}
1918 }
1919 
1920 static inline Framebuffer::TexTarget mapGLFboTexTarget (deUint32 target)
1921 {
1922 	switch (target)
1923 	{
1924 		case GL_TEXTURE_2D:						return Framebuffer::TEXTARGET_2D;
1925 		case GL_TEXTURE_CUBE_MAP_POSITIVE_X:	return Framebuffer::TEXTARGET_CUBE_MAP_POSITIVE_X;
1926 		case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:	return Framebuffer::TEXTARGET_CUBE_MAP_POSITIVE_Y;
1927 		case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:	return Framebuffer::TEXTARGET_CUBE_MAP_POSITIVE_Z;
1928 		case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:	return Framebuffer::TEXTARGET_CUBE_MAP_NEGATIVE_X;
1929 		case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:	return Framebuffer::TEXTARGET_CUBE_MAP_NEGATIVE_Y;
1930 		case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:	return Framebuffer::TEXTARGET_CUBE_MAP_NEGATIVE_Z;
1931 		default:								return Framebuffer::TEXTARGET_LAST;
1932 	}
1933 }
1934 
1935 void ReferenceContext::acquireFboAttachmentReference (const Framebuffer::Attachment& attachment)
1936 {
1937 	switch (attachment.type)
1938 	{
1939 		case Framebuffer::ATTACHMENTTYPE_TEXTURE:
1940 		{
1941 			TCU_CHECK(attachment.name != 0);
1942 			Texture* texture = m_textures.find(attachment.name);
1943 			TCU_CHECK(texture);
1944 			m_textures.acquireReference(texture);
1945 			break;
1946 		}
1947 
1948 		case Framebuffer::ATTACHMENTTYPE_RENDERBUFFER:
1949 		{
1950 			TCU_CHECK(attachment.name != 0);
1951 			Renderbuffer* rbo = m_renderbuffers.find(attachment.name);
1952 			TCU_CHECK(rbo);
1953 			m_renderbuffers.acquireReference(rbo);
1954 			break;
1955 		}
1956 
1957 		default:
1958 			break; // Silently ignore
1959 	}
1960 }
1961 
1962 void ReferenceContext::releaseFboAttachmentReference (const Framebuffer::Attachment& attachment)
1963 {
1964 	switch (attachment.type)
1965 	{
1966 		case Framebuffer::ATTACHMENTTYPE_TEXTURE:
1967 		{
1968 			TCU_CHECK(attachment.name != 0);
1969 			Texture* texture = m_textures.find(attachment.name);
1970 			TCU_CHECK(texture);
1971 			m_textures.releaseReference(texture);
1972 			break;
1973 		}
1974 
1975 		case Framebuffer::ATTACHMENTTYPE_RENDERBUFFER:
1976 		{
1977 			TCU_CHECK(attachment.name != 0);
1978 			Renderbuffer* rbo = m_renderbuffers.find(attachment.name);
1979 			TCU_CHECK(rbo);
1980 			m_renderbuffers.releaseReference(rbo);
1981 			break;
1982 		}
1983 
1984 		default:
1985 			break; // Silently ignore
1986 	}
1987 }
1988 
1989 void ReferenceContext::framebufferTexture2D (deUint32 target, deUint32 attachment, deUint32 textarget, deUint32 texture, int level)
1990 {
1991 	if (attachment == GL_DEPTH_STENCIL_ATTACHMENT)
1992 	{
1993 		// Attach to both depth and stencil.
1994 		framebufferTexture2D(target, GL_DEPTH_ATTACHMENT,	textarget, texture, level);
1995 		framebufferTexture2D(target, GL_STENCIL_ATTACHMENT,	textarget, texture, level);
1996 	}
1997 	else
1998 	{
1999 		Framebuffer::AttachmentPoint	point			= mapGLAttachmentPoint(attachment);
2000 		Texture*						texObj			= DE_NULL;
2001 		Framebuffer::TexTarget			fboTexTarget	= mapGLFboTexTarget(textarget);
2002 
2003 		RC_IF_ERROR(target != GL_FRAMEBUFFER		&&
2004 					target != GL_DRAW_FRAMEBUFFER	&&
2005 					target != GL_READ_FRAMEBUFFER,				GL_INVALID_ENUM,		RC_RET_VOID);
2006 		RC_IF_ERROR(point == Framebuffer::ATTACHMENTPOINT_LAST,	GL_INVALID_ENUM,		RC_RET_VOID);
2007 
2008 		// Select binding point.
2009 		rc::Framebuffer* framebufferBinding = (target == GL_FRAMEBUFFER || target == GL_DRAW_FRAMEBUFFER) ? m_drawFramebufferBinding : m_readFramebufferBinding;
2010 		RC_IF_ERROR(!framebufferBinding, GL_INVALID_OPERATION, RC_RET_VOID);
2011 
2012 		// If framebuffer object is bound for both reading and writing then we need to acquire/release multiple references.
2013 		int bindingRefCount = (framebufferBinding == m_drawFramebufferBinding ? 1 : 0)
2014 							+ (framebufferBinding == m_readFramebufferBinding ? 1 : 0);
2015 
2016 		if (texture != 0)
2017 		{
2018 			texObj = m_textures.find(texture);
2019 
2020 			RC_IF_ERROR(!texObj,		GL_INVALID_OPERATION,	RC_RET_VOID);
2021 			RC_IF_ERROR(level != 0,		GL_INVALID_VALUE,		RC_RET_VOID); // \todo [2012-03-19 pyry] We should allow other levels as well.
2022 
2023 			if (texObj->getType() == Texture::TYPE_2D)
2024 				RC_IF_ERROR(fboTexTarget != Framebuffer::TEXTARGET_2D, GL_INVALID_OPERATION, RC_RET_VOID);
2025 			else
2026 			{
2027 				TCU_CHECK(texObj->getType() == Texture::TYPE_CUBE_MAP);
2028 				if (!deInRange32(fboTexTarget, Framebuffer::TEXTARGET_CUBE_MAP_POSITIVE_X, Framebuffer::TEXTARGET_CUBE_MAP_NEGATIVE_Z))
2029 					RC_ERROR_RET(GL_INVALID_OPERATION, RC_RET_VOID);
2030 			}
2031 		}
2032 
2033 		Framebuffer::Attachment& fboAttachment = framebufferBinding->getAttachment(point);
2034 		for (int ndx = 0; ndx < bindingRefCount; ndx++)
2035 			releaseFboAttachmentReference(fboAttachment);
2036 		fboAttachment = Framebuffer::Attachment();
2037 
2038 		if (texObj)
2039 		{
2040 			fboAttachment.type			= Framebuffer::ATTACHMENTTYPE_TEXTURE;
2041 			fboAttachment.name			= texObj->getName();
2042 			fboAttachment.texTarget		= fboTexTarget;
2043 			fboAttachment.level			= level;
2044 
2045 			for (int ndx = 0; ndx < bindingRefCount; ndx++)
2046 				acquireFboAttachmentReference(fboAttachment);
2047 		}
2048 	}
2049 }
2050 
2051 void ReferenceContext::framebufferTextureLayer (deUint32 target, deUint32 attachment, deUint32 texture, int level, int layer)
2052 {
2053 	if (attachment == GL_DEPTH_STENCIL_ATTACHMENT)
2054 	{
2055 		// Attach to both depth and stencil.
2056 		framebufferTextureLayer(target, GL_DEPTH_ATTACHMENT,	texture, level, layer);
2057 		framebufferTextureLayer(target, GL_STENCIL_ATTACHMENT,	texture, level, layer);
2058 	}
2059 	else
2060 	{
2061 		Framebuffer::AttachmentPoint	point			= mapGLAttachmentPoint(attachment);
2062 		Texture*						texObj			= DE_NULL;
2063 
2064 		RC_IF_ERROR(target != GL_FRAMEBUFFER		&&
2065 					target != GL_DRAW_FRAMEBUFFER	&&
2066 					target != GL_READ_FRAMEBUFFER,				GL_INVALID_ENUM,		RC_RET_VOID);
2067 		RC_IF_ERROR(point == Framebuffer::ATTACHMENTPOINT_LAST,	GL_INVALID_ENUM,		RC_RET_VOID);
2068 
2069 		// Select binding point.
2070 		rc::Framebuffer* framebufferBinding = (target == GL_FRAMEBUFFER || target == GL_DRAW_FRAMEBUFFER) ? m_drawFramebufferBinding : m_readFramebufferBinding;
2071 		RC_IF_ERROR(!framebufferBinding, GL_INVALID_OPERATION, RC_RET_VOID);
2072 
2073 		// If framebuffer object is bound for both reading and writing then we need to acquire/release multiple references.
2074 		int bindingRefCount = (framebufferBinding == m_drawFramebufferBinding ? 1 : 0)
2075 							+ (framebufferBinding == m_readFramebufferBinding ? 1 : 0);
2076 
2077 		if (texture != 0)
2078 		{
2079 			texObj = m_textures.find(texture);
2080 
2081 			RC_IF_ERROR(!texObj,		GL_INVALID_OPERATION,	RC_RET_VOID);
2082 			RC_IF_ERROR(level != 0,		GL_INVALID_VALUE,		RC_RET_VOID); // \todo [2012-03-19 pyry] We should allow other levels as well.
2083 
2084 			RC_IF_ERROR(texObj->getType() != Texture::TYPE_2D_ARRAY			&&
2085 						texObj->getType() != Texture::TYPE_3D				&&
2086 						texObj->getType() != Texture::TYPE_CUBE_MAP_ARRAY,				GL_INVALID_OPERATION,	RC_RET_VOID);
2087 
2088 			if (texObj->getType() == Texture::TYPE_2D_ARRAY || texObj->getType() == Texture::TYPE_CUBE_MAP_ARRAY)
2089 			{
2090 				RC_IF_ERROR((layer < 0) || (layer >= GL_MAX_ARRAY_TEXTURE_LAYERS),		GL_INVALID_VALUE,		RC_RET_VOID);
2091 				RC_IF_ERROR((level < 0) || (level > deLog2Floor32(GL_MAX_TEXTURE_SIZE)),GL_INVALID_VALUE,		RC_RET_VOID);
2092 			}
2093 			else if	(texObj->getType() == Texture::TYPE_3D)
2094 			{
2095 				RC_IF_ERROR((layer < 0) || (layer >= GL_MAX_3D_TEXTURE_SIZE),				GL_INVALID_VALUE,		RC_RET_VOID);
2096 				RC_IF_ERROR((level < 0) || (level > deLog2Floor32(GL_MAX_3D_TEXTURE_SIZE)),	GL_INVALID_VALUE,		RC_RET_VOID);
2097 			}
2098 		}
2099 
2100 		Framebuffer::Attachment& fboAttachment = framebufferBinding->getAttachment(point);
2101 		for (int ndx = 0; ndx < bindingRefCount; ndx++)
2102 			releaseFboAttachmentReference(fboAttachment);
2103 		fboAttachment = Framebuffer::Attachment();
2104 
2105 		if (texObj)
2106 		{
2107 			fboAttachment.type			= Framebuffer::ATTACHMENTTYPE_TEXTURE;
2108 			fboAttachment.name			= texObj->getName();
2109 			fboAttachment.texTarget		= texLayeredTypeToTarget(texObj->getType());
2110 			fboAttachment.level			= level;
2111 			fboAttachment.layer			= layer;
2112 
2113 			DE_ASSERT(fboAttachment.texTarget != Framebuffer::TEXTARGET_LAST);
2114 
2115 			for (int ndx = 0; ndx < bindingRefCount; ndx++)
2116 				acquireFboAttachmentReference(fboAttachment);
2117 		}
2118 	}
2119 }
2120 
2121 void ReferenceContext::framebufferRenderbuffer (deUint32 target, deUint32 attachment, deUint32 renderbuffertarget, deUint32 renderbuffer)
2122 {
2123 	if (attachment == GL_DEPTH_STENCIL_ATTACHMENT)
2124 	{
2125 		// Attach both to depth and stencil.
2126 		framebufferRenderbuffer(target, GL_DEPTH_ATTACHMENT,	renderbuffertarget, renderbuffer);
2127 		framebufferRenderbuffer(target, GL_STENCIL_ATTACHMENT,	renderbuffertarget, renderbuffer);
2128 	}
2129 	else
2130 	{
2131 		Framebuffer::AttachmentPoint	point			= mapGLAttachmentPoint(attachment);
2132 		Renderbuffer*					rbo				= DE_NULL;
2133 
2134 		RC_IF_ERROR(target != GL_FRAMEBUFFER		&&
2135 					target != GL_DRAW_FRAMEBUFFER	&&
2136 					target != GL_READ_FRAMEBUFFER,				GL_INVALID_ENUM,		RC_RET_VOID);
2137 		RC_IF_ERROR(point == Framebuffer::ATTACHMENTPOINT_LAST,	GL_INVALID_ENUM,		RC_RET_VOID);
2138 
2139 		// Select binding point.
2140 		rc::Framebuffer* framebufferBinding = (target == GL_FRAMEBUFFER || target == GL_DRAW_FRAMEBUFFER) ? m_drawFramebufferBinding : m_readFramebufferBinding;
2141 		RC_IF_ERROR(!framebufferBinding, GL_INVALID_OPERATION, RC_RET_VOID);
2142 
2143 		// If framebuffer object is bound for both reading and writing then we need to acquire/release multiple references.
2144 		int bindingRefCount = (framebufferBinding == m_drawFramebufferBinding ? 1 : 0)
2145 							+ (framebufferBinding == m_readFramebufferBinding ? 1 : 0);
2146 
2147 		if (renderbuffer != 0)
2148 		{
2149 			rbo = m_renderbuffers.find(renderbuffer);
2150 
2151 			RC_IF_ERROR(renderbuffertarget != GL_RENDERBUFFER,	GL_INVALID_ENUM,		RC_RET_VOID);
2152 			RC_IF_ERROR(!rbo,									GL_INVALID_OPERATION,	RC_RET_VOID);
2153 		}
2154 
2155 		Framebuffer::Attachment& fboAttachment = framebufferBinding->getAttachment(point);
2156 		for (int ndx = 0; ndx < bindingRefCount; ndx++)
2157 			releaseFboAttachmentReference(fboAttachment);
2158 		fboAttachment = Framebuffer::Attachment();
2159 
2160 		if (rbo)
2161 		{
2162 			fboAttachment.type	= Framebuffer::ATTACHMENTTYPE_RENDERBUFFER;
2163 			fboAttachment.name	= rbo->getName();
2164 
2165 			for (int ndx = 0; ndx < bindingRefCount; ndx++)
2166 				acquireFboAttachmentReference(fboAttachment);
2167 		}
2168 	}
2169 }
2170 
2171 deUint32 ReferenceContext::checkFramebufferStatus (deUint32 target)
2172 {
2173 	RC_IF_ERROR(target != GL_FRAMEBUFFER		&&
2174 				target != GL_DRAW_FRAMEBUFFER	&&
2175 				target != GL_READ_FRAMEBUFFER, GL_INVALID_ENUM, 0);
2176 
2177 	// Select binding point.
2178 	rc::Framebuffer* framebufferBinding = (target == GL_FRAMEBUFFER || target == GL_DRAW_FRAMEBUFFER) ? m_drawFramebufferBinding : m_readFramebufferBinding;
2179 
2180 	// Default framebuffer is always complete.
2181 	if (!framebufferBinding)
2182 		return GL_FRAMEBUFFER_COMPLETE;
2183 
2184 	int		width				= -1;
2185 	int		height				= -1;
2186 	bool	hasAttachment		= false;
2187 	bool	attachmentComplete	= true;
2188 	bool	dimensionsOk		= true;
2189 
2190 	for (int point = 0; point < Framebuffer::ATTACHMENTPOINT_LAST; point++)
2191 	{
2192 		const Framebuffer::Attachment&	attachment			= framebufferBinding->getAttachment((Framebuffer::AttachmentPoint)point);
2193 		int								attachmentWidth		= 0;
2194 		int								attachmentHeight	= 0;
2195 		tcu::TextureFormat				attachmentFormat;
2196 
2197 		if (attachment.type == Framebuffer::ATTACHMENTTYPE_TEXTURE)
2198 		{
2199 			const Texture*					texture	= m_textures.find(attachment.name);
2200 			tcu::ConstPixelBufferAccess		level;
2201 			TCU_CHECK(texture);
2202 
2203 			if (attachment.texTarget == Framebuffer::TEXTARGET_2D)
2204 			{
2205 				DE_ASSERT(texture->getType() == Texture::TYPE_2D);
2206 				const Texture2D* tex2D = static_cast<const Texture2D*>(texture);
2207 
2208 				if (tex2D->hasLevel(attachment.level))
2209 					level = tex2D->getLevel(attachment.level);
2210 			}
2211 			else if (deInRange32(attachment.texTarget, Framebuffer::TEXTARGET_CUBE_MAP_POSITIVE_X,
2212 													   Framebuffer::TEXTARGET_CUBE_MAP_NEGATIVE_Z))
2213 			{
2214 				DE_ASSERT(texture->getType() == Texture::TYPE_CUBE_MAP);
2215 
2216 				const TextureCube*	texCube	= static_cast<const TextureCube*>(texture);
2217 				const tcu::CubeFace	face	= texTargetToFace(attachment.texTarget);
2218 				TCU_CHECK(de::inBounds<int>(face, 0, tcu::CUBEFACE_LAST));
2219 
2220 				if (texCube->hasFace(attachment.level, face))
2221 					level = texCube->getFace(attachment.level, face);
2222 			}
2223 			else if (attachment.texTarget == Framebuffer::TEXTARGET_2D_ARRAY)
2224 			{
2225 				DE_ASSERT(texture->getType() == Texture::TYPE_2D_ARRAY);
2226 				const Texture2DArray* tex2DArr = static_cast<const Texture2DArray*>(texture);
2227 
2228 				if (tex2DArr->hasLevel(attachment.level))
2229 					level = tex2DArr->getLevel(attachment.level); // \note Slice doesn't matter here.
2230 			}
2231 			else if (attachment.texTarget == Framebuffer::TEXTARGET_3D)
2232 			{
2233 				DE_ASSERT(texture->getType() == Texture::TYPE_3D);
2234 				const Texture3D* tex3D = static_cast<const Texture3D*>(texture);
2235 
2236 				if (tex3D->hasLevel(attachment.level))
2237 					level = tex3D->getLevel(attachment.level); // \note Slice doesn't matter here.
2238 			}
2239 			else if (attachment.texTarget == Framebuffer::TEXTARGET_CUBE_MAP_ARRAY)
2240 			{
2241 				DE_ASSERT(texture->getType() == Texture::TYPE_CUBE_MAP_ARRAY);
2242 				const TextureCubeArray* texCubeArr = static_cast<const TextureCubeArray*>(texture);
2243 
2244 				if (texCubeArr->hasLevel(attachment.level))
2245 					level = texCubeArr->getLevel(attachment.level); // \note Slice doesn't matter here.
2246 			}
2247 			else
2248 				TCU_FAIL("Framebuffer attached to a texture but no valid target specified");
2249 
2250 			attachmentWidth		= level.getWidth();
2251 			attachmentHeight	= level.getHeight();
2252 			attachmentFormat	= level.getFormat();
2253 		}
2254 		else if (attachment.type == Framebuffer::ATTACHMENTTYPE_RENDERBUFFER)
2255 		{
2256 			const Renderbuffer* renderbuffer = m_renderbuffers.find(attachment.name);
2257 			TCU_CHECK(renderbuffer);
2258 
2259 			attachmentWidth		= renderbuffer->getWidth();
2260 			attachmentHeight	= renderbuffer->getHeight();
2261 			attachmentFormat	= renderbuffer->getFormat();
2262 		}
2263 		else
2264 		{
2265 			TCU_CHECK(attachment.type == Framebuffer::ATTACHMENTTYPE_LAST);
2266 			continue; // Skip rest of checks.
2267 		}
2268 
2269 		if (!hasAttachment && attachmentWidth > 0 && attachmentHeight > 0)
2270 		{
2271 			width			= attachmentWidth;
2272 			height			= attachmentHeight;
2273 			hasAttachment	= true;
2274 		}
2275 		else if (attachmentWidth != width || attachmentHeight != height)
2276 			dimensionsOk = false;
2277 
2278 		// Validate attachment point compatibility.
2279 		switch (attachmentFormat.order)
2280 		{
2281 			case TextureFormat::R:
2282 			case TextureFormat::RG:
2283 			case TextureFormat::RGB:
2284 			case TextureFormat::RGBA:
2285 			case TextureFormat::sRGB:
2286 			case TextureFormat::sRGBA:
2287 				if (point != Framebuffer::ATTACHMENTPOINT_COLOR0)
2288 					attachmentComplete = false;
2289 				break;
2290 
2291 			case TextureFormat::D:
2292 				if (point != Framebuffer::ATTACHMENTPOINT_DEPTH)
2293 					attachmentComplete = false;
2294 				break;
2295 
2296 			case TextureFormat::S:
2297 				if (point != Framebuffer::ATTACHMENTPOINT_STENCIL)
2298 					attachmentComplete = false;
2299 				break;
2300 
2301 			case TextureFormat::DS:
2302 				if (point != Framebuffer::ATTACHMENTPOINT_DEPTH &&
2303 					point != Framebuffer::ATTACHMENTPOINT_STENCIL)
2304 					attachmentComplete = false;
2305 				break;
2306 
2307 			default:
2308 				TCU_FAIL("Unsupported attachment channel order");
2309 		}
2310 	}
2311 
2312 	if (!attachmentComplete)
2313 		return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
2314 	else if (!hasAttachment)
2315 		return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
2316 	else if (!dimensionsOk)
2317 		return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
2318 	else
2319 		return GL_FRAMEBUFFER_COMPLETE;
2320 }
2321 
2322 void ReferenceContext::getFramebufferAttachmentParameteriv (deUint32 target, deUint32 attachment, deUint32 pname, int* params)
2323 {
2324 	DE_UNREF(target && attachment && pname && params);
2325 	TCU_CHECK(false); // \todo [pyry] Implement
2326 }
2327 
2328 void ReferenceContext::renderbufferStorage (deUint32 target, deUint32 internalformat, int width, int height)
2329 {
2330 	TextureFormat format = glu::mapGLInternalFormat(internalformat);
2331 
2332 	RC_IF_ERROR(target != GL_RENDERBUFFER, GL_INVALID_ENUM, RC_RET_VOID);
2333 	RC_IF_ERROR(!m_renderbufferBinding, GL_INVALID_OPERATION, RC_RET_VOID);
2334 	RC_IF_ERROR(!deInRange32(width, 0, m_limits.maxRenderbufferSize) ||
2335 				!deInRange32(height, 0, m_limits.maxRenderbufferSize),
2336 				GL_INVALID_OPERATION, RC_RET_VOID);
2337 	RC_IF_ERROR(format.order == TextureFormat::CHANNELORDER_LAST ||
2338 				format.type == TextureFormat::CHANNELTYPE_LAST, GL_INVALID_ENUM, RC_RET_VOID);
2339 
2340 	m_renderbufferBinding->setStorage(format, (int)width, (int)height);
2341 }
2342 
2343 void ReferenceContext::renderbufferStorageMultisample (deUint32 target, int samples, deUint32 internalFormat, int width, int height)
2344 {
2345 	// \todo [2012-04-07 pyry] Implement MSAA support.
2346 	DE_UNREF(samples);
2347 	renderbufferStorage(target, internalFormat, width, height);
2348 }
2349 
2350 tcu::PixelBufferAccess ReferenceContext::getFboAttachment (const rc::Framebuffer& framebuffer, rc::Framebuffer::AttachmentPoint point)
2351 {
2352 	const Framebuffer::Attachment& attachment = framebuffer.getAttachment(point);
2353 
2354 	switch (attachment.type)
2355 	{
2356 		case Framebuffer::ATTACHMENTTYPE_TEXTURE:
2357 		{
2358 			Texture* texture = m_textures.find(attachment.name);
2359 			TCU_CHECK(texture);
2360 
2361 			if (texture->getType() == Texture::TYPE_2D)
2362 			{
2363 				if (Texture2D* texture2D = dynamic_cast<Texture2D*>(texture))
2364 					return texture2D->getLevel(attachment.level);
2365 				else
2366 					return nullAccess();
2367 			}
2368 			else if (texture->getType() == Texture::TYPE_CUBE_MAP)
2369 			{
2370 				if (TextureCube* cubeMap = dynamic_cast<TextureCube*>(texture))
2371 					return cubeMap->getFace(attachment.level, texTargetToFace(attachment.texTarget));
2372 				else
2373 					return nullAccess();
2374 			}
2375 			else if (texture->getType() == Texture::TYPE_2D_ARRAY	||
2376 					 texture->getType() == Texture::TYPE_3D			||
2377 					 texture->getType() == Texture::TYPE_CUBE_MAP_ARRAY)
2378 			{
2379 				tcu::PixelBufferAccess level;
2380 
2381 				if (texture->getType() == Texture::TYPE_2D_ARRAY)
2382 				{
2383 					if (Texture2DArray* texture2DArray = dynamic_cast<Texture2DArray*>(texture))
2384 						level = texture2DArray->getLevel(attachment.level);
2385 				}
2386 				else if (texture->getType() == Texture::TYPE_3D)
2387 				{
2388 					if (Texture3D* texture3D = dynamic_cast<Texture3D*>(texture))
2389 						level = texture3D->getLevel(attachment.level);
2390 				}
2391 				else if (texture->getType() == Texture::TYPE_CUBE_MAP_ARRAY)
2392 				{
2393 					if (TextureCubeArray* cubeArray = dynamic_cast<TextureCubeArray*>(texture))
2394 						level = cubeArray->getLevel(attachment.level);
2395 				}
2396 
2397 				void* layerData = static_cast<deUint8*>(level.getDataPtr()) + level.getSlicePitch() * attachment.layer;
2398 
2399 				return tcu::PixelBufferAccess(level.getFormat(), level.getWidth(), level.getHeight(), 1, level.getRowPitch(), 0, layerData);
2400 			}
2401 			else
2402 				return nullAccess();
2403 		}
2404 
2405 		case Framebuffer::ATTACHMENTTYPE_RENDERBUFFER:
2406 		{
2407 			Renderbuffer* rbo = m_renderbuffers.find(attachment.name);
2408 			TCU_CHECK(rbo);
2409 
2410 			return rbo->getAccess();
2411 		}
2412 
2413 		default:
2414 			return nullAccess();
2415 	}
2416 }
2417 
2418 const Texture2D& ReferenceContext::getTexture2D (int unitNdx) const
2419 {
2420 	const TextureUnit& unit = m_textureUnits[unitNdx];
2421 	return unit.tex2DBinding ? *unit.tex2DBinding : unit.default2DTex;
2422 }
2423 
2424 const TextureCube& ReferenceContext::getTextureCube (int unitNdx) const
2425 {
2426 	const TextureUnit& unit = m_textureUnits[unitNdx];
2427 	return unit.texCubeBinding ? *unit.texCubeBinding : unit.defaultCubeTex;
2428 }
2429 
2430 static bool isValidBufferTarget (deUint32 target)
2431 {
2432 	switch (target)
2433 	{
2434 		case GL_ARRAY_BUFFER:
2435 		case GL_COPY_READ_BUFFER:
2436 		case GL_COPY_WRITE_BUFFER:
2437 		case GL_DRAW_INDIRECT_BUFFER:
2438 		case GL_ELEMENT_ARRAY_BUFFER:
2439 		case GL_PIXEL_PACK_BUFFER:
2440 		case GL_PIXEL_UNPACK_BUFFER:
2441 		case GL_TRANSFORM_FEEDBACK_BUFFER:
2442 		case GL_UNIFORM_BUFFER:
2443 			return true;
2444 
2445 		default:
2446 			return false;
2447 	}
2448 }
2449 
2450 void ReferenceContext::setBufferBinding (deUint32 target, DataBuffer* buffer)
2451 {
2452 	DataBuffer** bindingPoint = DE_NULL;
2453 	VertexArray* vertexArrayObject = (m_vertexArrayBinding) ? (m_vertexArrayBinding) : (&m_clientVertexArray);
2454 
2455 	switch (target)
2456 	{
2457 		case GL_ARRAY_BUFFER:				bindingPoint = &m_arrayBufferBinding;								break;
2458 		case GL_COPY_READ_BUFFER:			bindingPoint = &m_copyReadBufferBinding;							break;
2459 		case GL_COPY_WRITE_BUFFER:			bindingPoint = &m_copyWriteBufferBinding;							break;
2460 		case GL_DRAW_INDIRECT_BUFFER:		bindingPoint = &m_drawIndirectBufferBinding;						break;
2461 		case GL_ELEMENT_ARRAY_BUFFER:		bindingPoint = &vertexArrayObject->m_elementArrayBufferBinding;		break;
2462 		case GL_PIXEL_PACK_BUFFER:			bindingPoint = &m_pixelPackBufferBinding;							break;
2463 		case GL_PIXEL_UNPACK_BUFFER:		bindingPoint = &m_pixelUnpackBufferBinding;							break;
2464 		case GL_TRANSFORM_FEEDBACK_BUFFER:	bindingPoint = &m_transformFeedbackBufferBinding;					break;
2465 		case GL_UNIFORM_BUFFER:				bindingPoint = &m_uniformBufferBinding;								break;
2466 		default:
2467 			DE_ASSERT(false);
2468 			return;
2469 	}
2470 
2471 	if (*bindingPoint)
2472 	{
2473 		m_buffers.releaseReference(*bindingPoint);
2474 		*bindingPoint = DE_NULL;
2475 	}
2476 
2477 	if (buffer)
2478 		m_buffers.acquireReference(buffer);
2479 
2480 	*bindingPoint = buffer;
2481 }
2482 
2483 DataBuffer* ReferenceContext::getBufferBinding (deUint32 target) const
2484 {
2485 	const VertexArray* vertexArrayObject = (m_vertexArrayBinding) ? (m_vertexArrayBinding) : (&m_clientVertexArray);
2486 
2487 	switch (target)
2488 	{
2489 		case GL_ARRAY_BUFFER:				return m_arrayBufferBinding;
2490 		case GL_COPY_READ_BUFFER:			return m_copyReadBufferBinding;
2491 		case GL_COPY_WRITE_BUFFER:			return m_copyWriteBufferBinding;
2492 		case GL_DRAW_INDIRECT_BUFFER:		return m_drawIndirectBufferBinding;
2493 		case GL_ELEMENT_ARRAY_BUFFER:		return vertexArrayObject->m_elementArrayBufferBinding;
2494 		case GL_PIXEL_PACK_BUFFER:			return m_pixelPackBufferBinding;
2495 		case GL_PIXEL_UNPACK_BUFFER:		return m_pixelUnpackBufferBinding;
2496 		case GL_TRANSFORM_FEEDBACK_BUFFER:	return m_transformFeedbackBufferBinding;
2497 		case GL_UNIFORM_BUFFER:				return m_uniformBufferBinding;
2498 		default:
2499 			DE_ASSERT(false);
2500 			return DE_NULL;
2501 	}
2502 }
2503 
2504 void ReferenceContext::bindBuffer (deUint32 target, deUint32 buffer)
2505 {
2506 	RC_IF_ERROR(!isValidBufferTarget(target), GL_INVALID_ENUM, RC_RET_VOID);
2507 
2508 	rc::DataBuffer*	bufObj	= DE_NULL;
2509 
2510 	if (buffer != 0)
2511 	{
2512 		bufObj = m_buffers.find(buffer);
2513 		if (!bufObj)
2514 		{
2515 			bufObj = new DataBuffer(buffer);
2516 			m_buffers.insert(bufObj);
2517 		}
2518 	}
2519 
2520 	setBufferBinding(target, bufObj);
2521 }
2522 
2523 void ReferenceContext::genBuffers (int numBuffers, deUint32* buffers)
2524 {
2525 	RC_IF_ERROR(!buffers, GL_INVALID_VALUE, RC_RET_VOID);
2526 
2527 	for (int ndx = 0; ndx < numBuffers; ndx++)
2528 		buffers[ndx] = m_buffers.allocateName();
2529 }
2530 
2531 void ReferenceContext::deleteBuffers (int numBuffers, const deUint32* buffers)
2532 {
2533 	RC_IF_ERROR(numBuffers < 0, GL_INVALID_VALUE, RC_RET_VOID);
2534 
2535 	for (int ndx = 0; ndx < numBuffers; ndx++)
2536 	{
2537 		deUint32	buffer	= buffers[ndx];
2538 		DataBuffer*	bufObj	= DE_NULL;
2539 
2540 		if (buffer == 0)
2541 			continue;
2542 
2543 		bufObj = m_buffers.find(buffer);
2544 
2545 		if (bufObj)
2546 			deleteBuffer(bufObj);
2547 	}
2548 }
2549 
2550 void ReferenceContext::deleteBuffer (DataBuffer* buffer)
2551 {
2552 	static const deUint32 bindingPoints[] =
2553 	{
2554 		GL_ARRAY_BUFFER,
2555 		GL_COPY_READ_BUFFER,
2556 		GL_COPY_WRITE_BUFFER,
2557 		GL_DRAW_INDIRECT_BUFFER,
2558 		GL_ELEMENT_ARRAY_BUFFER,
2559 		GL_PIXEL_PACK_BUFFER,
2560 		GL_PIXEL_UNPACK_BUFFER,
2561 		GL_TRANSFORM_FEEDBACK_BUFFER,
2562 		GL_UNIFORM_BUFFER
2563 	};
2564 
2565 	for (int bindingNdx = 0; bindingNdx < DE_LENGTH_OF_ARRAY(bindingPoints); bindingNdx++)
2566 	{
2567 		if (getBufferBinding(bindingPoints[bindingNdx]) == buffer)
2568 			setBufferBinding(bindingPoints[bindingNdx], DE_NULL);
2569 	}
2570 
2571 	{
2572 		vector<VertexArray*> vertexArrays;
2573 		m_vertexArrays.getAll(vertexArrays);
2574 		vertexArrays.push_back(&m_clientVertexArray);
2575 
2576 		for (vector<VertexArray*>::iterator i = vertexArrays.begin(); i != vertexArrays.end(); i++)
2577 		{
2578 			if ((*i)->m_elementArrayBufferBinding == buffer)
2579 			{
2580 				m_buffers.releaseReference(buffer);
2581 				(*i)->m_elementArrayBufferBinding = DE_NULL;
2582 			}
2583 
2584 			for (size_t vertexAttribNdx = 0; vertexAttribNdx < (*i)->m_arrays.size(); ++vertexAttribNdx)
2585 			{
2586 				if ((*i)->m_arrays[vertexAttribNdx].bufferBinding == buffer)
2587 				{
2588 					m_buffers.releaseReference(buffer);
2589 					(*i)->m_arrays[vertexAttribNdx].bufferDeleted = true;
2590 					(*i)->m_arrays[vertexAttribNdx].bufferBinding = DE_NULL;
2591 				}
2592 			}
2593 		}
2594 	}
2595 
2596 	DE_ASSERT(buffer->getRefCount() == 1);
2597 	m_buffers.releaseReference(buffer);
2598 }
2599 
2600 void ReferenceContext::bufferData (deUint32 target, deIntptr size, const void* data, deUint32 usage)
2601 {
2602 	RC_IF_ERROR(!isValidBufferTarget(target), GL_INVALID_ENUM, RC_RET_VOID);
2603 	RC_IF_ERROR(size < 0, GL_INVALID_VALUE, RC_RET_VOID);
2604 
2605 	DE_UNREF(usage);
2606 
2607 	DataBuffer* buffer = getBufferBinding(target);
2608 	RC_IF_ERROR(!buffer, GL_INVALID_OPERATION, RC_RET_VOID);
2609 
2610 	DE_ASSERT((deIntptr)(int)size == size);
2611 	buffer->setStorage((int)size);
2612 	if (data)
2613 		deMemcpy(buffer->getData(), data, (int)size);
2614 }
2615 
2616 void ReferenceContext::bufferSubData (deUint32 target, deIntptr offset, deIntptr size, const void* data)
2617 {
2618 	RC_IF_ERROR(!isValidBufferTarget(target), GL_INVALID_ENUM, RC_RET_VOID);
2619 	RC_IF_ERROR(offset < 0 || size < 0, GL_INVALID_VALUE, RC_RET_VOID);
2620 
2621 	DataBuffer* buffer = getBufferBinding(target);
2622 
2623 	RC_IF_ERROR(!buffer, GL_INVALID_OPERATION, RC_RET_VOID);
2624 	RC_IF_ERROR((int)(offset+size) > buffer->getSize(), GL_INVALID_VALUE, RC_RET_VOID);
2625 
2626 	deMemcpy(buffer->getData()+offset, data, (int)size);
2627 }
2628 
2629 void ReferenceContext::clearColor (float red, float green, float blue, float alpha)
2630 {
2631 	m_clearColor = Vec4(de::clamp(red,	0.0f, 1.0f),
2632 						de::clamp(green,	0.0f, 1.0f),
2633 						de::clamp(blue,	0.0f, 1.0f),
2634 						de::clamp(alpha,	0.0f, 1.0f));
2635 }
2636 
2637 void ReferenceContext::clearDepthf (float depth)
2638 {
2639 	m_clearDepth = de::clamp(depth, 0.0f, 1.0f);
2640 }
2641 
2642 void ReferenceContext::clearStencil (int stencil)
2643 {
2644 	m_clearStencil = stencil;
2645 }
2646 
2647 void ReferenceContext::scissor (int x, int y, int width, int height)
2648 {
2649 	RC_IF_ERROR(width < 0 || height < 0, GL_INVALID_VALUE, RC_RET_VOID);
2650 	m_scissorBox = IVec4(x, y, width, height);
2651 }
2652 
2653 void ReferenceContext::enable (deUint32 cap)
2654 {
2655 	switch (cap)
2656 	{
2657 		case GL_BLEND:					m_blendEnabled				= true;	break;
2658 		case GL_SCISSOR_TEST:			m_scissorEnabled			= true;	break;
2659 		case GL_DEPTH_TEST:				m_depthTestEnabled			= true;	break;
2660 		case GL_STENCIL_TEST:			m_stencilTestEnabled		= true;	break;
2661 		case GL_POLYGON_OFFSET_FILL:	m_polygonOffsetFillEnabled	= true;	break;
2662 
2663 		case GL_FRAMEBUFFER_SRGB:
2664 			if (glu::isContextTypeGLCore(getType()))
2665 			{
2666 				m_sRGBUpdateEnabled = true;
2667 				break;
2668 			}
2669 			setError(GL_INVALID_ENUM);
2670 			break;
2671 
2672 		case GL_DEPTH_CLAMP:
2673 			if (glu::isContextTypeGLCore(getType()))
2674 			{
2675 				m_depthClampEnabled = true;
2676 				break;
2677 			}
2678 			setError(GL_INVALID_ENUM);
2679 			break;
2680 
2681 		case GL_DITHER:
2682 			// Not implemented - just ignored.
2683 			break;
2684 
2685 		case GL_PRIMITIVE_RESTART_FIXED_INDEX:
2686 			if (!glu::isContextTypeGLCore(getType()))
2687 			{
2688 				m_primitiveRestartFixedIndex = true;
2689 				break;
2690 			}
2691 			setError(GL_INVALID_ENUM);
2692 			break;
2693 
2694 		case GL_PRIMITIVE_RESTART:
2695 			if (glu::isContextTypeGLCore(getType()))
2696 			{
2697 				m_primitiveRestartSettableIndex = true;
2698 				break;
2699 			}
2700 			setError(GL_INVALID_ENUM);
2701 			break;
2702 
2703 		default:
2704 			setError(GL_INVALID_ENUM);
2705 			break;
2706 	}
2707 }
2708 
2709 void ReferenceContext::disable (deUint32 cap)
2710 {
2711 	switch (cap)
2712 	{
2713 		case GL_BLEND:					m_blendEnabled				= false;	break;
2714 		case GL_SCISSOR_TEST:			m_scissorEnabled			= false;	break;
2715 		case GL_DEPTH_TEST:				m_depthTestEnabled			= false;	break;
2716 		case GL_STENCIL_TEST:			m_stencilTestEnabled		= false;	break;
2717 		case GL_POLYGON_OFFSET_FILL:	m_polygonOffsetFillEnabled	= false;	break;
2718 
2719 		case GL_FRAMEBUFFER_SRGB:
2720 			if (glu::isContextTypeGLCore(getType()))
2721 			{
2722 				m_sRGBUpdateEnabled = false;
2723 				break;
2724 			}
2725 			setError(GL_INVALID_ENUM);
2726 			break;
2727 
2728 		case GL_DEPTH_CLAMP:
2729 			if (glu::isContextTypeGLCore(getType()))
2730 			{
2731 				m_depthClampEnabled = false;
2732 				break;
2733 			}
2734 			setError(GL_INVALID_ENUM);
2735 			break;
2736 
2737 		case GL_DITHER:
2738 			break;
2739 
2740 		case GL_PRIMITIVE_RESTART_FIXED_INDEX:
2741 			if (!glu::isContextTypeGLCore(getType()))
2742 			{
2743 				m_primitiveRestartFixedIndex = false;
2744 				break;
2745 			}
2746 			setError(GL_INVALID_ENUM);
2747 			break;
2748 
2749 		case GL_PRIMITIVE_RESTART:
2750 			if (glu::isContextTypeGLCore(getType()))
2751 			{
2752 				m_primitiveRestartSettableIndex = false;
2753 				break;
2754 			}
2755 			setError(GL_INVALID_ENUM);
2756 			break;
2757 
2758 		default:
2759 			setError(GL_INVALID_ENUM);
2760 			break;
2761 	}
2762 }
2763 
2764 static bool isValidCompareFunc (deUint32 func)
2765 {
2766 	switch (func)
2767 	{
2768 		case GL_NEVER:
2769 		case GL_LESS:
2770 		case GL_LEQUAL:
2771 		case GL_GREATER:
2772 		case GL_GEQUAL:
2773 		case GL_EQUAL:
2774 		case GL_NOTEQUAL:
2775 		case GL_ALWAYS:
2776 			return true;
2777 
2778 		default:
2779 			return false;
2780 	}
2781 }
2782 
2783 static bool isValidStencilOp (deUint32 op)
2784 {
2785 	switch (op)
2786 	{
2787 		case GL_KEEP:
2788 		case GL_ZERO:
2789 		case GL_REPLACE:
2790 		case GL_INCR:
2791 		case GL_INCR_WRAP:
2792 		case GL_DECR:
2793 		case GL_DECR_WRAP:
2794 		case GL_INVERT:
2795 			return true;
2796 
2797 		default:
2798 			return false;
2799 	}
2800 }
2801 
2802 void ReferenceContext::stencilFunc (deUint32 func, int ref, deUint32 mask)
2803 {
2804 	stencilFuncSeparate(GL_FRONT_AND_BACK, func, ref, mask);
2805 }
2806 
2807 void ReferenceContext::stencilFuncSeparate (deUint32 face, deUint32 func, int ref, deUint32 mask)
2808 {
2809 	const bool	setFront	= face == GL_FRONT || face == GL_FRONT_AND_BACK;
2810 	const bool	setBack		= face == GL_BACK || face == GL_FRONT_AND_BACK;
2811 
2812 	RC_IF_ERROR(!isValidCompareFunc(func), GL_INVALID_ENUM, RC_RET_VOID);
2813 	RC_IF_ERROR(!setFront && !setBack, GL_INVALID_ENUM, RC_RET_VOID);
2814 
2815 	for (int type = 0; type < rr::FACETYPE_LAST; ++type)
2816 	{
2817 		if ((type == rr::FACETYPE_FRONT && setFront) ||
2818 			(type == rr::FACETYPE_BACK && setBack))
2819 		{
2820 			m_stencil[type].func	= func;
2821 			m_stencil[type].ref		= ref;
2822 			m_stencil[type].opMask	= mask;
2823 		}
2824 	}
2825 }
2826 
2827 void ReferenceContext::stencilOp (deUint32 sfail, deUint32 dpfail, deUint32 dppass)
2828 {
2829 	stencilOpSeparate(GL_FRONT_AND_BACK, sfail, dpfail, dppass);
2830 }
2831 
2832 void ReferenceContext::stencilOpSeparate (deUint32 face, deUint32 sfail, deUint32 dpfail, deUint32 dppass)
2833 {
2834 	const bool	setFront	= face == GL_FRONT || face == GL_FRONT_AND_BACK;
2835 	const bool	setBack		= face == GL_BACK || face == GL_FRONT_AND_BACK;
2836 
2837 	RC_IF_ERROR(!isValidStencilOp(sfail)	||
2838 				!isValidStencilOp(dpfail)	||
2839 				!isValidStencilOp(dppass),
2840 				GL_INVALID_ENUM, RC_RET_VOID);
2841 	RC_IF_ERROR(!setFront && !setBack, GL_INVALID_ENUM, RC_RET_VOID);
2842 
2843 	for (int type = 0; type < rr::FACETYPE_LAST; ++type)
2844 	{
2845 		if ((type == rr::FACETYPE_FRONT && setFront) ||
2846 			(type == rr::FACETYPE_BACK && setBack))
2847 		{
2848 			m_stencil[type].opStencilFail	= sfail;
2849 			m_stencil[type].opDepthFail		= dpfail;
2850 			m_stencil[type].opDepthPass		= dppass;
2851 		}
2852 	}
2853 }
2854 
2855 void ReferenceContext::depthFunc (deUint32 func)
2856 {
2857 	RC_IF_ERROR(!isValidCompareFunc(func), GL_INVALID_ENUM, RC_RET_VOID);
2858 	m_depthFunc = func;
2859 }
2860 
2861 void ReferenceContext::depthRangef (float n, float f)
2862 {
2863 	m_depthRangeNear = de::clamp(n, 0.0f, 1.0f);
2864 	m_depthRangeFar = de::clamp(f, 0.0f, 1.0f);
2865 }
2866 
2867 void ReferenceContext::depthRange (double n, double f)
2868 {
2869 	depthRangef((float)n, (float)f);
2870 }
2871 
2872 void ReferenceContext::polygonOffset (float factor, float units)
2873 {
2874 	m_polygonOffsetFactor = factor;
2875 	m_polygonOffsetUnits = units;
2876 }
2877 
2878 void ReferenceContext::provokingVertex (deUint32 convention)
2879 {
2880 	// only in core
2881 	DE_ASSERT(glu::isContextTypeGLCore(getType()));
2882 
2883 	switch (convention)
2884 	{
2885 		case GL_FIRST_VERTEX_CONVENTION:	m_provokingFirstVertexConvention = true; break;
2886 		case GL_LAST_VERTEX_CONVENTION:		m_provokingFirstVertexConvention = false; break;
2887 
2888 		default:
2889 			RC_ERROR_RET(GL_INVALID_ENUM, RC_RET_VOID);
2890 	}
2891 }
2892 
2893 void ReferenceContext::primitiveRestartIndex (deUint32 index)
2894 {
2895 	// only in core
2896 	DE_ASSERT(glu::isContextTypeGLCore(getType()));
2897 	m_primitiveRestartIndex = index;
2898 }
2899 
2900 static inline bool isValidBlendEquation (deUint32 mode)
2901 {
2902 	return mode == GL_FUNC_ADD				||
2903 		   mode == GL_FUNC_SUBTRACT			||
2904 		   mode == GL_FUNC_REVERSE_SUBTRACT	||
2905 		   mode == GL_MIN					||
2906 		   mode == GL_MAX;
2907 }
2908 
2909 static bool isValidBlendFactor (deUint32 factor)
2910 {
2911 	switch (factor)
2912 	{
2913 		case GL_ZERO:
2914 		case GL_ONE:
2915 		case GL_SRC_COLOR:
2916 		case GL_ONE_MINUS_SRC_COLOR:
2917 		case GL_DST_COLOR:
2918 		case GL_ONE_MINUS_DST_COLOR:
2919 		case GL_SRC_ALPHA:
2920 		case GL_ONE_MINUS_SRC_ALPHA:
2921 		case GL_DST_ALPHA:
2922 		case GL_ONE_MINUS_DST_ALPHA:
2923 		case GL_CONSTANT_COLOR:
2924 		case GL_ONE_MINUS_CONSTANT_COLOR:
2925 		case GL_CONSTANT_ALPHA:
2926 		case GL_ONE_MINUS_CONSTANT_ALPHA:
2927 		case GL_SRC_ALPHA_SATURATE:
2928 			return true;
2929 
2930 		default:
2931 			return false;
2932 	}
2933 }
2934 
2935 void ReferenceContext::blendEquation (deUint32 mode)
2936 {
2937 	RC_IF_ERROR(!isValidBlendEquation(mode), GL_INVALID_ENUM, RC_RET_VOID);
2938 
2939 	m_blendModeRGB		= mode;
2940 	m_blendModeAlpha	= mode;
2941 }
2942 
2943 void ReferenceContext::blendEquationSeparate (deUint32 modeRGB, deUint32 modeAlpha)
2944 {
2945 	RC_IF_ERROR(!isValidBlendEquation(modeRGB) ||
2946 				!isValidBlendEquation(modeAlpha),
2947 				GL_INVALID_ENUM, RC_RET_VOID);
2948 
2949 	m_blendModeRGB		= modeRGB;
2950 	m_blendModeAlpha	= modeAlpha;
2951 }
2952 
2953 void ReferenceContext::blendFunc (deUint32 src, deUint32 dst)
2954 {
2955 	RC_IF_ERROR(!isValidBlendFactor(src) ||
2956 				!isValidBlendFactor(dst),
2957 				GL_INVALID_ENUM, RC_RET_VOID);
2958 
2959 	m_blendFactorSrcRGB		= src;
2960 	m_blendFactorSrcAlpha	= src;
2961 	m_blendFactorDstRGB		= dst;
2962 	m_blendFactorDstAlpha	= dst;
2963 }
2964 
2965 void ReferenceContext::blendFuncSeparate (deUint32 srcRGB, deUint32 dstRGB, deUint32 srcAlpha, deUint32 dstAlpha)
2966 {
2967 	RC_IF_ERROR(!isValidBlendFactor(srcRGB)		||
2968 				!isValidBlendFactor(dstRGB)		||
2969 				!isValidBlendFactor(srcAlpha)	||
2970 				!isValidBlendFactor(dstAlpha),
2971 				GL_INVALID_ENUM, RC_RET_VOID);
2972 
2973 	m_blendFactorSrcRGB		= srcRGB;
2974 	m_blendFactorSrcAlpha	= srcAlpha;
2975 	m_blendFactorDstRGB		= dstRGB;
2976 	m_blendFactorDstAlpha	= dstAlpha;
2977 }
2978 
2979 void ReferenceContext::blendColor (float red, float green, float blue, float alpha)
2980 {
2981 	m_blendColor = Vec4(de::clamp(red,	0.0f, 1.0f),
2982 						de::clamp(green,	0.0f, 1.0f),
2983 						de::clamp(blue,	0.0f, 1.0f),
2984 						de::clamp(alpha,	0.0f, 1.0f));
2985 }
2986 
2987 void ReferenceContext::colorMask (deBool r, deBool g, deBool b, deBool a)
2988 {
2989 	m_colorMask = tcu::BVec4(!!r, !!g, !!b, !!a);
2990 }
2991 
2992 void ReferenceContext::depthMask (deBool mask)
2993 {
2994 	m_depthMask = !!mask;
2995 }
2996 
2997 void ReferenceContext::stencilMask (deUint32 mask)
2998 {
2999 	stencilMaskSeparate(GL_FRONT_AND_BACK, mask);
3000 }
3001 
3002 void ReferenceContext::stencilMaskSeparate (deUint32 face, deUint32 mask)
3003 {
3004 	const bool	setFront	= face == GL_FRONT || face == GL_FRONT_AND_BACK;
3005 	const bool	setBack		= face == GL_BACK || face == GL_FRONT_AND_BACK;
3006 
3007 	RC_IF_ERROR(!setFront && !setBack, GL_INVALID_ENUM, RC_RET_VOID);
3008 
3009 	if (setFront)	m_stencil[rr::FACETYPE_FRONT].writeMask	= mask;
3010 	if (setBack)	m_stencil[rr::FACETYPE_BACK].writeMask	= mask;
3011 }
3012 
3013 static int getNumStencilBits (const tcu::TextureFormat& format)
3014 {
3015 	switch (format.order)
3016 	{
3017 		case tcu::TextureFormat::S:
3018 			switch (format.type)
3019 			{
3020 				case tcu::TextureFormat::UNSIGNED_INT8:		return 8;
3021 				case tcu::TextureFormat::UNSIGNED_INT16:	return 16;
3022 				case tcu::TextureFormat::UNSIGNED_INT32:	return 32;
3023 				default:
3024 					DE_ASSERT(false);
3025 					return 0;
3026 			}
3027 
3028 		case tcu::TextureFormat::DS:
3029 			switch (format.type)
3030 			{
3031 				case tcu::TextureFormat::UNSIGNED_INT_24_8:				return 8;
3032 				case tcu::TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:	return 8;
3033 				default:
3034 					DE_ASSERT(false);
3035 					return 0;
3036 			}
3037 
3038 		default:
3039 			DE_ASSERT(false);
3040 			return 0;
3041 	}
3042 }
3043 
3044 static inline deUint32 maskStencil (int numBits, deUint32 s)
3045 {
3046 	return s & deBitMask32(0, numBits);
3047 }
3048 
3049 static inline void writeMaskedStencil (const rr::MultisamplePixelBufferAccess& access, int s, int x, int y, deUint32 stencil, deUint32 writeMask)
3050 {
3051 	DE_ASSERT(access.raw().getFormat().order == tcu::TextureFormat::S);
3052 
3053 	const deUint32 oldVal = access.raw().getPixelUint(s, x, y).x();
3054 	const deUint32 newVal = (oldVal & ~writeMask) | (stencil & writeMask);
3055 	access.raw().setPixel(tcu::UVec4(newVal, 0u, 0u, 0u), s, x, y);
3056 }
3057 
3058 static inline void writeDepthOnly (const rr::MultisamplePixelBufferAccess& access, int s, int x, int y, float depth)
3059 {
3060 	access.raw().setPixDepth(depth, s, x, y);
3061 }
3062 
3063 static rr::MultisamplePixelBufferAccess getDepthMultisampleAccess (const rr::MultisamplePixelBufferAccess& combinedDSaccess)
3064 {
3065 	return rr::MultisamplePixelBufferAccess::fromMultisampleAccess(tcu::getEffectiveDepthStencilAccess(combinedDSaccess.raw(), tcu::Sampler::MODE_DEPTH));
3066 }
3067 
3068 static rr::MultisamplePixelBufferAccess getStencilMultisampleAccess (const rr::MultisamplePixelBufferAccess& combinedDSaccess)
3069 {
3070 	return rr::MultisamplePixelBufferAccess::fromMultisampleAccess(tcu::getEffectiveDepthStencilAccess(combinedDSaccess.raw(), tcu::Sampler::MODE_STENCIL));
3071 }
3072 
3073 deUint32 ReferenceContext::blitResolveMultisampleFramebuffer (deUint32 mask, const IVec4& srcRect, const IVec4& dstRect, bool flipX, bool flipY)
3074 {
3075 	if (mask & GL_COLOR_BUFFER_BIT)
3076 	{
3077 		rr::MultisampleConstPixelBufferAccess	src			= rr::getSubregion(getReadColorbuffer(), srcRect.x(), srcRect.y(), srcRect.z(), srcRect.w());
3078 		tcu::PixelBufferAccess					dst			= tcu::getSubregion(getDrawColorbuffer().toSinglesampleAccess(), dstRect.x(), dstRect.y(), dstRect.z(), dstRect.w());
3079 		tcu::TextureChannelClass				dstClass	= tcu::getTextureChannelClass(dst.getFormat().type);
3080 		bool									dstIsFloat	= dstClass == tcu::TEXTURECHANNELCLASS_FLOATING_POINT		||
3081 															  dstClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT	||
3082 															  dstClass == tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT;
3083 		bool									srcIsSRGB	= tcu::isSRGB(src.raw().getFormat());
3084 		bool									dstIsSRGB	= tcu::isSRGB(dst.getFormat());
3085 		const bool								convertSRGB	= m_sRGBUpdateEnabled && glu::isContextTypeES(getType());
3086 
3087 		if (!convertSRGB)
3088 		{
3089 			tcu::ConstPixelBufferAccess	srcRaw	= src.raw();
3090 			tcu::TextureFormat			srcFmt	= toNonSRGBFormat(srcRaw.getFormat());
3091 
3092 			srcRaw	= tcu::ConstPixelBufferAccess(srcFmt, srcRaw.getWidth(), srcRaw.getHeight(), srcRaw.getDepth(), srcRaw.getRowPitch(), srcRaw.getSlicePitch(), srcRaw.getDataPtr());
3093 			src		= rr::MultisampleConstPixelBufferAccess::fromMultisampleAccess(srcRaw);
3094 
3095 			dst		= tcu::PixelBufferAccess(toNonSRGBFormat(dst.getFormat()), dst.getWidth(), dst.getHeight(), dst.getDepth(), dst.getRowPitch(), dst.getSlicePitch(), dst.getDataPtr());
3096 		}
3097 
3098 		for (int x = 0; x < dstRect.z(); ++x)
3099 		for (int y = 0; y < dstRect.w(); ++y)
3100 		{
3101 			int srcX = (flipX) ? (srcRect.z() - x - 1) : (x);
3102 			int srcY = (flipY) ? (srcRect.z() - y - 1) : (y);
3103 
3104 			if (dstIsFloat || srcIsSRGB)
3105 			{
3106 				Vec4 p = src.raw().getPixel(0, srcX,srcY);
3107 				dst.setPixel((dstIsSRGB && convertSRGB) ? tcu::linearToSRGB(p) : p, x, y);
3108 			}
3109 			else
3110 				dst.setPixel(src.raw().getPixelInt(0, srcX, srcY), x, y);
3111 		}
3112 	}
3113 
3114 	if (mask & GL_DEPTH_BUFFER_BIT)
3115 	{
3116 		rr::MultisampleConstPixelBufferAccess	src	= rr::getSubregion(getReadDepthbuffer(), srcRect.x(), srcRect.y(), srcRect.z(), srcRect.w());
3117 		rr::MultisamplePixelBufferAccess		dst	= rr::getSubregion(getDrawDepthbuffer(), dstRect.x(), dstRect.y(), dstRect.z(), dstRect.w());
3118 
3119 		for (int x = 0; x < dstRect.z(); ++x)
3120 		for (int y = 0; y < dstRect.w(); ++y)
3121 		{
3122 			int srcX = (flipX) ? (srcRect.z() - x - 1) : (x);
3123 			int srcY = (flipY) ? (srcRect.z() - y - 1) : (y);
3124 
3125 			writeDepthOnly(dst, 0, x, y, src.raw().getPixel(0, srcX, srcY).x());
3126 		}
3127 	}
3128 
3129 	if (mask & GL_STENCIL_BUFFER_BIT)
3130 	{
3131 		rr::MultisampleConstPixelBufferAccess	src	= getStencilMultisampleAccess(rr::getSubregion(getReadStencilbuffer(), srcRect.x(), srcRect.y(), srcRect.z(), srcRect.w()));
3132 		rr::MultisamplePixelBufferAccess		dst	= getStencilMultisampleAccess(rr::getSubregion(getDrawStencilbuffer(), dstRect.x(), dstRect.y(), dstRect.z(), dstRect.w()));
3133 
3134 		for (int x = 0; x < dstRect.z(); ++x)
3135 		for (int y = 0; y < dstRect.w(); ++y)
3136 		{
3137 			int			srcX		= (flipX) ? (srcRect.z() - x - 1) : (x);
3138 			int			srcY		= (flipY) ? (srcRect.z() - y - 1) : (y);
3139 			deUint32	srcStencil	= src.raw().getPixelUint(0, srcX, srcY).x();
3140 
3141 			writeMaskedStencil(dst, 0, x, y, srcStencil, m_stencil[rr::FACETYPE_FRONT].writeMask);
3142 		}
3143 	}
3144 
3145 	return GL_NO_ERROR;
3146 }
3147 
3148 void ReferenceContext::blitFramebuffer (int srcX0, int srcY0, int srcX1, int srcY1, int dstX0, int dstY0, int dstX1, int dstY1, deUint32 mask, deUint32 filter)
3149 {
3150 	// p0 in inclusive, p1 exclusive.
3151 	// Negative width/height means swap.
3152 	bool	swapSrcX	= srcX1 < srcX0;
3153 	bool	swapSrcY	= srcY1 < srcY0;
3154 	bool	swapDstX	= dstX1 < dstX0;
3155 	bool	swapDstY	= dstY1 < dstY0;
3156 	int		srcW		= de::abs(srcX1-srcX0);
3157 	int		srcH		= de::abs(srcY1-srcY0);
3158 	int		dstW		= de::abs(dstX1-dstX0);
3159 	int		dstH		= de::abs(dstY1-dstY0);
3160 	bool	scale		= srcW != dstW || srcH != dstH;
3161 	int		srcOriginX	= swapSrcX ? srcX1 : srcX0;
3162 	int		srcOriginY	= swapSrcY ? srcY1 : srcY0;
3163 	int		dstOriginX	= swapDstX ? dstX1 : dstX0;
3164 	int		dstOriginY	= swapDstY ? dstY1 : dstY0;
3165 	IVec4	srcRect		= IVec4(srcOriginX, srcOriginY, srcW, srcH);
3166 	IVec4	dstRect		= IVec4(dstOriginX, dstOriginY, dstW, dstH);
3167 
3168 	RC_IF_ERROR(filter != GL_NEAREST && filter != GL_LINEAR, GL_INVALID_ENUM, RC_RET_VOID);
3169 	RC_IF_ERROR((mask & (GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT)) != 0 && filter != GL_NEAREST, GL_INVALID_OPERATION, RC_RET_VOID);
3170 
3171 	// Validate that both targets are complete.
3172 	RC_IF_ERROR(checkFramebufferStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE ||
3173 				checkFramebufferStatus(GL_READ_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE, GL_INVALID_OPERATION, RC_RET_VOID);
3174 
3175 	// Check samples count is valid
3176 	RC_IF_ERROR(getDrawColorbuffer().getNumSamples() != 1, GL_INVALID_OPERATION, RC_RET_VOID);
3177 
3178 	// Check size restrictions of multisampled case
3179 	if (getReadColorbuffer().getNumSamples() != 1)
3180 	{
3181 		// Src and Dst rect dimensions must be the same
3182 		RC_IF_ERROR(srcW != dstW || srcH != dstH, GL_INVALID_OPERATION, RC_RET_VOID);
3183 
3184 		// Framebuffer formats must match
3185 		if (mask & GL_COLOR_BUFFER_BIT)		RC_IF_ERROR(getReadColorbuffer().raw().getFormat()   != getDrawColorbuffer().raw().getFormat(),   GL_INVALID_OPERATION, RC_RET_VOID);
3186 		if (mask & GL_DEPTH_BUFFER_BIT)		RC_IF_ERROR(getReadDepthbuffer().raw().getFormat()   != getDrawDepthbuffer().raw().getFormat(),   GL_INVALID_OPERATION, RC_RET_VOID);
3187 		if (mask & GL_STENCIL_BUFFER_BIT)	RC_IF_ERROR(getReadStencilbuffer().raw().getFormat() != getDrawStencilbuffer().raw().getFormat(), GL_INVALID_OPERATION, RC_RET_VOID);
3188 	}
3189 
3190 	// Compute actual source rect.
3191 	srcRect = (mask & GL_COLOR_BUFFER_BIT)		? intersect(srcRect, getBufferRect(getReadColorbuffer()))	: srcRect;
3192 	srcRect = (mask & GL_DEPTH_BUFFER_BIT)		? intersect(srcRect, getBufferRect(getReadDepthbuffer()))	: srcRect;
3193 	srcRect = (mask & GL_STENCIL_BUFFER_BIT)	? intersect(srcRect, getBufferRect(getReadStencilbuffer()))	: srcRect;
3194 
3195 	// Compute destination rect.
3196 	dstRect = (mask & GL_COLOR_BUFFER_BIT)		? intersect(dstRect, getBufferRect(getDrawColorbuffer()))	: dstRect;
3197 	dstRect = (mask & GL_DEPTH_BUFFER_BIT)		? intersect(dstRect, getBufferRect(getDrawDepthbuffer()))	: dstRect;
3198 	dstRect = (mask & GL_STENCIL_BUFFER_BIT)	? intersect(dstRect, getBufferRect(getDrawStencilbuffer()))	: dstRect;
3199 	dstRect = m_scissorEnabled					? intersect(dstRect, m_scissorBox)							: dstRect;
3200 
3201 	if (isEmpty(srcRect) || isEmpty(dstRect))
3202 		return; // Don't attempt copy.
3203 
3204 	// Multisampled read buffer is a special case
3205 	if (getReadColorbuffer().getNumSamples() != 1)
3206 	{
3207 		deUint32 error = blitResolveMultisampleFramebuffer(mask, srcRect, dstRect, swapSrcX ^ swapDstX, swapSrcY ^ swapDstY);
3208 
3209 		if (error != GL_NO_ERROR)
3210 			setError(error);
3211 
3212 		return;
3213 	}
3214 
3215 	// \note Multisample pixel buffers can now be accessed like non-multisampled because multisample read buffer case is already handled. => sample count must be 1
3216 
3217 	// Coordinate transformation:
3218 	// Dst offset space -> dst rectangle space -> src rectangle space -> src offset space.
3219 	tcu::Mat3 transform = tcu::translationMatrix(Vec2((float)(srcX0 - srcRect.x()), (float)(srcY0 - srcRect.y())))
3220 						* tcu::Mat3(Vec3((float)(srcX1-srcX0) / (float)(dstX1-dstX0),
3221 										 (float)(srcY1-srcY0) / (float)(dstY1-dstY0),
3222 										 1.0f))
3223 						* tcu::translationMatrix(Vec2((float)(dstRect.x() - dstX0), (float)(dstRect.y() - dstY0)));
3224 
3225 	if (mask & GL_COLOR_BUFFER_BIT)
3226 	{
3227 		tcu::ConstPixelBufferAccess		src			= tcu::getSubregion(getReadColorbuffer().toSinglesampleAccess(), srcRect.x(), srcRect.y(), srcRect.z(), srcRect.w());
3228 		tcu::PixelBufferAccess			dst			= tcu::getSubregion(getDrawColorbuffer().toSinglesampleAccess(), dstRect.x(), dstRect.y(), dstRect.z(), dstRect.w());
3229 		tcu::TextureChannelClass		dstClass	= tcu::getTextureChannelClass(dst.getFormat().type);
3230 		bool							dstIsFloat	= dstClass == tcu::TEXTURECHANNELCLASS_FLOATING_POINT		||
3231 													  dstClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT	||
3232 													  dstClass == tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT;
3233 		tcu::Sampler::FilterMode		sFilter		= (scale && filter == GL_LINEAR) ? tcu::Sampler::LINEAR : tcu::Sampler::NEAREST;
3234 		tcu::Sampler					sampler		(tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE,
3235 													 sFilter, sFilter, 0.0f /* lod threshold */, false /* non-normalized coords */);
3236 		bool							srcIsSRGB	= tcu::isSRGB(src.getFormat());
3237 		bool							dstIsSRGB	= tcu::isSRGB(dst.getFormat());
3238 		const bool						convertSRGB	= m_sRGBUpdateEnabled && glu::isContextTypeES(getType());
3239 
3240 		if (!convertSRGB)
3241 		{
3242 			src	= tcu::ConstPixelBufferAccess	(toNonSRGBFormat(src.getFormat()), src.getWidth(), src.getHeight(), src.getDepth(), src.getRowPitch(), src.getSlicePitch(), src.getDataPtr());
3243 			dst	= tcu::PixelBufferAccess		(toNonSRGBFormat(dst.getFormat()), dst.getWidth(), dst.getHeight(), dst.getDepth(), dst.getRowPitch(), dst.getSlicePitch(), dst.getDataPtr());
3244 		}
3245 
3246 		// \note We don't check for unsupported conversions, unlike spec requires.
3247 
3248 		for (int yo = 0; yo < dstRect.w(); yo++)
3249 		{
3250 			for (int xo = 0; xo < dstRect.z(); xo++)
3251 			{
3252 				float	dX	= (float)xo + 0.5f;
3253 				float	dY	= (float)yo + 0.5f;
3254 
3255 				// \note Only affine part is used.
3256 				float	sX	= transform(0, 0)*dX + transform(0, 1)*dY + transform(0, 2);
3257 				float	sY	= transform(1, 0)*dX + transform(1, 1)*dY + transform(1, 2);
3258 
3259 				// do not copy pixels outside the modified source region (modified by buffer intersection)
3260 				if (sX < 0.0f || sX >= (float)srcRect.z() ||
3261 					sY < 0.0f || sY >= (float)srcRect.w())
3262 					continue;
3263 
3264 				if (dstIsFloat || srcIsSRGB || filter == tcu::Sampler::LINEAR)
3265 				{
3266 					Vec4 p = src.sample2D(sampler, sampler.minFilter, sX, sY, 0);
3267 					dst.setPixel((dstIsSRGB && convertSRGB) ? tcu::linearToSRGB(p) : p, xo, yo);
3268 				}
3269 				else
3270 					dst.setPixel(src.getPixelInt(deFloorFloatToInt32(sX), deFloorFloatToInt32(sY)), xo, yo);
3271 			}
3272 		}
3273 	}
3274 
3275 	if ((mask & GL_DEPTH_BUFFER_BIT) && m_depthMask)
3276 	{
3277 		rr::MultisampleConstPixelBufferAccess	src		= getDepthMultisampleAccess(rr::getSubregion(getReadDepthbuffer(), srcRect.x(), srcRect.y(), srcRect.z(), srcRect.w()));
3278 		rr::MultisamplePixelBufferAccess		dst		= getDepthMultisampleAccess(rr::getSubregion(getDrawDepthbuffer(), dstRect.x(), dstRect.y(), dstRect.z(), dstRect.w()));
3279 
3280 		for (int yo = 0; yo < dstRect.w(); yo++)
3281 		{
3282 			for (int xo = 0; xo < dstRect.z(); xo++)
3283 			{
3284 				const int sampleNdx = 0; // multisample read buffer case is already handled
3285 
3286 				float	dX	= (float)xo + 0.5f;
3287 				float	dY	= (float)yo + 0.5f;
3288 				float	sX	= transform(0, 0)*dX + transform(0, 1)*dY + transform(0, 2);
3289 				float	sY	= transform(1, 0)*dX + transform(1, 1)*dY + transform(1, 2);
3290 
3291 				writeDepthOnly(dst, sampleNdx, xo, yo, src.raw().getPixDepth(sampleNdx, deFloorFloatToInt32(sX), deFloorFloatToInt32(sY)));
3292 			}
3293 		}
3294 	}
3295 
3296 	if (mask & GL_STENCIL_BUFFER_BIT)
3297 	{
3298 		rr::MultisampleConstPixelBufferAccess	src	= getStencilMultisampleAccess(rr::getSubregion(getReadStencilbuffer(), srcRect.x(), srcRect.y(), srcRect.z(), srcRect.w()));
3299 		rr::MultisamplePixelBufferAccess		dst	= getStencilMultisampleAccess(rr::getSubregion(getDrawStencilbuffer(), dstRect.x(), dstRect.y(), dstRect.z(), dstRect.w()));
3300 
3301 		for (int yo = 0; yo < dstRect.w(); yo++)
3302 		{
3303 			for (int xo = 0; xo < dstRect.z(); xo++)
3304 			{
3305 				const int	sampleNdx = 0; // multisample read buffer case is already handled
3306 
3307 				float		dX			= (float)xo + 0.5f;
3308 				float		dY			= (float)yo + 0.5f;
3309 				float		sX			= transform(0, 0)*dX + transform(0, 1)*dY + transform(0, 2);
3310 				float		sY			= transform(1, 0)*dX + transform(1, 1)*dY + transform(1, 2);
3311 				deUint32	srcStencil	= src.raw().getPixelUint(sampleNdx, deFloorFloatToInt32(sX), deFloorFloatToInt32(sY)).x();
3312 
3313 				writeMaskedStencil(dst, sampleNdx, xo, yo, srcStencil, m_stencil[rr::FACETYPE_FRONT].writeMask);
3314 			}
3315 		}
3316 	}
3317 }
3318 
3319 void ReferenceContext::invalidateSubFramebuffer (deUint32 target, int numAttachments, const deUint32* attachments, int x, int y, int width, int height)
3320 {
3321 	RC_IF_ERROR(target != GL_FRAMEBUFFER, GL_INVALID_ENUM, RC_RET_VOID);
3322 	RC_IF_ERROR((numAttachments < 0) || (numAttachments > 1 && attachments == DE_NULL), GL_INVALID_VALUE, RC_RET_VOID);
3323 	RC_IF_ERROR(width < 0 || height < 0, GL_INVALID_VALUE, RC_RET_VOID);
3324 
3325 	// \todo [2012-07-17 pyry] Support multiple color attachments.
3326 
3327 	const Vec4		colorClearValue		(0.0f);
3328 	const float		depthClearValue		= 1.0f;
3329 	const int		stencilClearValue	= 0;
3330 
3331 	bool			isFboBound			= m_drawFramebufferBinding != DE_NULL;
3332 	bool			discardBuffers[3]	= { false, false, false }; // Color, depth, stencil
3333 
3334 	for (int attNdx = 0; attNdx < numAttachments; attNdx++)
3335 	{
3336 		bool	isColor			= attachments[attNdx] == (isFboBound ? GL_COLOR_ATTACHMENT0		: GL_COLOR);
3337 		bool	isDepth			= attachments[attNdx] == (isFboBound ? GL_DEPTH_ATTACHMENT		: GL_DEPTH);
3338 		bool	isStencil		= attachments[attNdx] == (isFboBound ? GL_STENCIL_ATTACHMENT	: GL_STENCIL);
3339 		bool	isDepthStencil	= isFboBound && attachments[attNdx] == GL_DEPTH_STENCIL_ATTACHMENT;
3340 
3341 		RC_IF_ERROR(!isColor && !isDepth && !isStencil && !isDepthStencil, GL_INVALID_VALUE, RC_RET_VOID);
3342 
3343 		if (isColor)						discardBuffers[0] = true;
3344 		if (isDepth || isDepthStencil)		discardBuffers[1] = true;
3345 		if (isStencil || isDepthStencil)	discardBuffers[2] = true;
3346 	}
3347 
3348 	for (int ndx = 0; ndx < 3; ndx++)
3349 	{
3350 		if (!discardBuffers[ndx])
3351 			continue;
3352 
3353 		bool								isColor					= ndx == 0;
3354 		bool								isDepth					= ndx == 1;
3355 		bool								isStencil				= ndx == 2;
3356 		rr::MultisamplePixelBufferAccess	buf						= isColor ? getDrawColorbuffer()								:
3357 																	  isDepth ? getDepthMultisampleAccess(getDrawDepthbuffer())		:
3358 																				getStencilMultisampleAccess(getDrawStencilbuffer());
3359 
3360 		if (isEmpty(buf))
3361 			continue;
3362 
3363 		tcu::IVec4							area					= intersect(tcu::IVec4(0, 0, buf.raw().getHeight(), buf.raw().getDepth()), tcu::IVec4(x, y, width, height));
3364 		rr::MultisamplePixelBufferAccess	access					= rr::getSubregion(buf, area.x(), area.y(), area.z(), area.w());
3365 
3366 		if (isColor)
3367 			rr::clear(access, colorClearValue);
3368 		else if (isDepth)
3369 			rr::clear(access, tcu::Vec4(depthClearValue));
3370 		else if (isStencil)
3371 			rr::clear(access, tcu::IVec4(stencilClearValue));
3372 	}
3373 }
3374 
3375 void ReferenceContext::invalidateFramebuffer (deUint32 target, int numAttachments, const deUint32* attachments)
3376 {
3377 	// \todo [2012-07-17 pyry] Support multiple color attachments.
3378 	rr::MultisampleConstPixelBufferAccess	colorBuf0	= getDrawColorbuffer();
3379 	rr::MultisampleConstPixelBufferAccess	depthBuf	= getDrawDepthbuffer();
3380 	rr::MultisampleConstPixelBufferAccess	stencilBuf	= getDrawStencilbuffer();
3381 	int										width		= 0;
3382 	int										height		= 0;
3383 
3384 	width = de::max(width, colorBuf0.raw().getHeight());
3385 	width = de::max(width, depthBuf.raw().getHeight());
3386 	width = de::max(width, stencilBuf.raw().getHeight());
3387 
3388 	height = de::max(height, colorBuf0.raw().getDepth());
3389 	height = de::max(height, depthBuf.raw().getDepth());
3390 	height = de::max(height, stencilBuf.raw().getDepth());
3391 
3392 	invalidateSubFramebuffer(target, numAttachments, attachments, 0, 0, width, height);
3393 }
3394 
3395 void ReferenceContext::clear (deUint32 buffers)
3396 {
3397 	RC_IF_ERROR((buffers & ~(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT)) != 0, GL_INVALID_VALUE, RC_RET_VOID);
3398 
3399 	rr::MultisamplePixelBufferAccess	colorBuf0	= getDrawColorbuffer();
3400 	rr::MultisamplePixelBufferAccess	depthBuf	= getDrawDepthbuffer();
3401 	rr::MultisamplePixelBufferAccess	stencilBuf	= getDrawStencilbuffer();
3402 	IVec4								baseArea	= m_scissorEnabled ? m_scissorBox : IVec4(0, 0, 0x7fffffff, 0x7fffffff);
3403 	IVec4								colorArea	= intersect(baseArea, getBufferRect(colorBuf0));
3404 	IVec4								depthArea	= intersect(baseArea, getBufferRect(depthBuf));
3405 	IVec4								stencilArea	= intersect(baseArea, getBufferRect(stencilBuf));
3406 	bool								hasColor0	= !isEmpty(colorArea);
3407 	bool								hasDepth	= !isEmpty(depthArea);
3408 	bool								hasStencil	= !isEmpty(stencilArea);
3409 
3410 	if (hasColor0 && (buffers & GL_COLOR_BUFFER_BIT) != 0)
3411 	{
3412 		rr::MultisamplePixelBufferAccess	access		= rr::getSubregion(colorBuf0, colorArea.x(), colorArea.y(), colorArea.z(), colorArea.w());
3413 		bool								isSRGB		= tcu::isSRGB(colorBuf0.raw().getFormat());
3414 		Vec4								c			= (isSRGB && m_sRGBUpdateEnabled) ? tcu::linearToSRGB(m_clearColor) : m_clearColor;
3415 		bool								maskUsed	= !m_colorMask[0] || !m_colorMask[1] || !m_colorMask[2] || !m_colorMask[3];
3416 		bool								maskZero	= !m_colorMask[0] && !m_colorMask[1] && !m_colorMask[2] && !m_colorMask[3];
3417 
3418 		if (!maskUsed)
3419 			rr::clear(access, c);
3420 		else if (!maskZero)
3421 		{
3422 			for (int y = 0; y < access.raw().getDepth(); y++)
3423 				for (int x = 0; x < access.raw().getHeight(); x++)
3424 					for (int s = 0; s < access.getNumSamples(); s++)
3425 						access.raw().setPixel(tcu::select(c, access.raw().getPixel(s, x, y), m_colorMask), s, x, y);
3426 		}
3427 		// else all channels masked out
3428 	}
3429 
3430 	if (hasDepth && (buffers & GL_DEPTH_BUFFER_BIT) != 0 && m_depthMask)
3431 	{
3432 		rr::MultisamplePixelBufferAccess access = getDepthMultisampleAccess(rr::getSubregion(depthBuf, depthArea.x(), depthArea.y(), depthArea.z(), depthArea.w()));
3433 		rr::clearDepth(access, m_clearDepth);
3434 	}
3435 
3436 	if (hasStencil && (buffers & GL_STENCIL_BUFFER_BIT) != 0)
3437 	{
3438 		rr::MultisamplePixelBufferAccess	access					= getStencilMultisampleAccess(rr::getSubregion(stencilBuf, stencilArea.x(), stencilArea.y(), stencilArea.z(), stencilArea.w()));
3439 		int									stencilBits				= getNumStencilBits(stencilBuf.raw().getFormat());
3440 		int									stencil					= maskStencil(stencilBits, m_clearStencil);
3441 
3442 		if ((m_stencil[rr::FACETYPE_FRONT].writeMask & ((1u<<stencilBits)-1u)) != ((1u<<stencilBits)-1u))
3443 		{
3444 			// Slow path where depth or stencil is masked out in write.
3445 			for (int y = 0; y < access.raw().getDepth(); y++)
3446 				for (int x = 0; x < access.raw().getHeight(); x++)
3447 					for (int s = 0; s < access.getNumSamples(); s++)
3448 						writeMaskedStencil(access, s, x, y, stencil, m_stencil[rr::FACETYPE_FRONT].writeMask);
3449 		}
3450 		else
3451 			rr::clearStencil(access, stencil);
3452 	}
3453 }
3454 
3455 void ReferenceContext::clearBufferiv (deUint32 buffer, int drawbuffer, const int* value)
3456 {
3457 	RC_IF_ERROR(buffer != GL_COLOR && buffer != GL_STENCIL, GL_INVALID_ENUM, RC_RET_VOID);
3458 	RC_IF_ERROR(drawbuffer != 0, GL_INVALID_VALUE, RC_RET_VOID); // \todo [2012-04-06 pyry] MRT support.
3459 
3460 	IVec4 baseArea = m_scissorEnabled ? m_scissorBox : IVec4(0, 0, 0x7fffffff, 0x7fffffff);
3461 
3462 	if (buffer == GL_COLOR)
3463 	{
3464 		rr::MultisamplePixelBufferAccess	colorBuf	= getDrawColorbuffer();
3465 		bool								maskUsed	= !m_colorMask[0] || !m_colorMask[1] || !m_colorMask[2] || !m_colorMask[3];
3466 		bool								maskZero	= !m_colorMask[0] && !m_colorMask[1] && !m_colorMask[2] && !m_colorMask[3];
3467 		IVec4								area		= intersect(baseArea, getBufferRect(colorBuf));
3468 
3469 		if (!isEmpty(area) && !maskZero)
3470 		{
3471 			rr::MultisamplePixelBufferAccess	access		= rr::getSubregion(colorBuf, area.x(), area.y(), area.z(), area.w());
3472 			IVec4								color		(value[0], value[1], value[2], value[3]);
3473 
3474 			if (!maskUsed)
3475 				rr::clear(access, color);
3476 			else
3477 			{
3478 				for (int y = 0; y < access.raw().getDepth(); y++)
3479 					for (int x = 0; x < access.raw().getHeight(); x++)
3480 						for (int s = 0; s < access.getNumSamples(); s++)
3481 							access.raw().setPixel(tcu::select(color, access.raw().getPixelInt(s, x, y), m_colorMask), s, x, y);
3482 			}
3483 		}
3484 	}
3485 	else
3486 	{
3487 		TCU_CHECK_INTERNAL(buffer == GL_STENCIL);
3488 
3489 		rr::MultisamplePixelBufferAccess	stencilBuf	= getDrawStencilbuffer();
3490 		IVec4								area		= intersect(baseArea, getBufferRect(stencilBuf));
3491 
3492 		if (!isEmpty(area) && m_stencil[rr::FACETYPE_FRONT].writeMask != 0)
3493 		{
3494 			rr::MultisamplePixelBufferAccess	access		= getStencilMultisampleAccess(rr::getSubregion(stencilBuf, area.x(), area.y(), area.z(), area.w()));
3495 			int									stencil		= value[0];
3496 
3497 			for (int y = 0; y < access.raw().getDepth(); y++)
3498 				for (int x = 0; x < access.raw().getHeight(); x++)
3499 					for (int s = 0; s < access.getNumSamples(); s++)
3500 						writeMaskedStencil(access, s, x, y, stencil, m_stencil[rr::FACETYPE_FRONT].writeMask);
3501 		}
3502 	}
3503 }
3504 
3505 void ReferenceContext::clearBufferfv (deUint32 buffer, int drawbuffer, const float* value)
3506 {
3507 	RC_IF_ERROR(buffer != GL_COLOR && buffer != GL_DEPTH, GL_INVALID_ENUM, RC_RET_VOID);
3508 	RC_IF_ERROR(drawbuffer != 0, GL_INVALID_VALUE, RC_RET_VOID); // \todo [2012-04-06 pyry] MRT support.
3509 
3510 	IVec4 baseArea = m_scissorEnabled ? m_scissorBox : IVec4(0, 0, 0x7fffffff, 0x7fffffff);
3511 
3512 	if (buffer == GL_COLOR)
3513 	{
3514 		rr::MultisamplePixelBufferAccess	colorBuf	= getDrawColorbuffer();
3515 		bool								maskUsed	= !m_colorMask[0] || !m_colorMask[1] || !m_colorMask[2] || !m_colorMask[3];
3516 		bool								maskZero	= !m_colorMask[0] && !m_colorMask[1] && !m_colorMask[2] && !m_colorMask[3];
3517 		IVec4								area		= intersect(baseArea, getBufferRect(colorBuf));
3518 
3519 		if (!isEmpty(area) && !maskZero)
3520 		{
3521 			rr::MultisamplePixelBufferAccess	access		= rr::getSubregion(colorBuf, area.x(), area.y(), area.z(), area.w());
3522 			Vec4								color		(value[0], value[1], value[2], value[3]);
3523 
3524 			if (m_sRGBUpdateEnabled && tcu::isSRGB(access.raw().getFormat()))
3525 				color = tcu::linearToSRGB(color);
3526 
3527 			if (!maskUsed)
3528 				rr::clear(access, color);
3529 			else
3530 			{
3531 				for (int y = 0; y < access.raw().getDepth(); y++)
3532 					for (int x = 0; x < access.raw().getHeight(); x++)
3533 						for (int s = 0; s < access.getNumSamples(); s++)
3534 							access.raw().setPixel(tcu::select(color, access.raw().getPixel(s, x, y), m_colorMask), s, x, y);
3535 			}
3536 		}
3537 	}
3538 	else
3539 	{
3540 		TCU_CHECK_INTERNAL(buffer == GL_DEPTH);
3541 
3542 		rr::MultisamplePixelBufferAccess	depthBuf	= getDrawDepthbuffer();
3543 		IVec4								area		= intersect(baseArea, getBufferRect(depthBuf));
3544 
3545 		if (!isEmpty(area) && m_depthMask)
3546 		{
3547 			rr::MultisamplePixelBufferAccess	access		= rr::getSubregion(depthBuf, area.x(), area.y(), area.z(), area.w());
3548 			float								depth		= value[0];
3549 
3550 			rr::clearDepth(access, depth);
3551 		}
3552 	}
3553 }
3554 
3555 void ReferenceContext::clearBufferuiv (deUint32 buffer, int drawbuffer, const deUint32* value)
3556 {
3557 	RC_IF_ERROR(buffer != GL_COLOR, GL_INVALID_ENUM, RC_RET_VOID);
3558 	RC_IF_ERROR(drawbuffer != 0, GL_INVALID_VALUE, RC_RET_VOID); // \todo [2012-04-06 pyry] MRT support.
3559 
3560 	IVec4 baseArea = m_scissorEnabled ? m_scissorBox : IVec4(0, 0, 0x7fffffff, 0x7fffffff);
3561 
3562 	TCU_CHECK_INTERNAL(buffer == GL_COLOR);
3563 	{
3564 		rr::MultisamplePixelBufferAccess	colorBuf	= getDrawColorbuffer();
3565 		bool								maskUsed	= !m_colorMask[0] || !m_colorMask[1] || !m_colorMask[2] || !m_colorMask[3];
3566 		bool								maskZero	= !m_colorMask[0] && !m_colorMask[1] && !m_colorMask[2] && !m_colorMask[3];
3567 		IVec4								area		= intersect(baseArea, getBufferRect(colorBuf));
3568 
3569 		if (!isEmpty(area) && !maskZero)
3570 		{
3571 			rr::MultisamplePixelBufferAccess	access		= rr::getSubregion(colorBuf, area.x(), area.y(), area.z(), area.w());
3572 			tcu::UVec4							color		(value[0], value[1], value[2], value[3]);
3573 
3574 			if (!maskUsed)
3575 				rr::clear(access, color.asInt());
3576 			else
3577 			{
3578 				for (int y = 0; y < access.raw().getDepth(); y++)
3579 					for (int x = 0; x < access.raw().getHeight(); x++)
3580 						for (int s = 0; s < access.getNumSamples(); s++)
3581 							access.raw().setPixel(tcu::select(color, access.raw().getPixelUint(s, x, y), m_colorMask), s, x, y);
3582 			}
3583 		}
3584 	}
3585 }
3586 
3587 void ReferenceContext::clearBufferfi (deUint32 buffer, int drawbuffer, float depth, int stencil)
3588 {
3589 	RC_IF_ERROR(buffer != GL_DEPTH_STENCIL, GL_INVALID_ENUM, RC_RET_VOID);
3590 	clearBufferfv(GL_DEPTH, drawbuffer, &depth);
3591 	clearBufferiv(GL_STENCIL, drawbuffer, &stencil);
3592 }
3593 
3594 void ReferenceContext::bindVertexArray (deUint32 array)
3595 {
3596 	rc::VertexArray* vertexArrayObject = DE_NULL;
3597 
3598 	if (array != 0)
3599 	{
3600 		vertexArrayObject = m_vertexArrays.find(array);
3601 		if (!vertexArrayObject)
3602 		{
3603 			vertexArrayObject = new rc::VertexArray(array, m_limits.maxVertexAttribs);
3604 			m_vertexArrays.insert(vertexArrayObject);
3605 		}
3606 	}
3607 
3608 	// Create new references
3609 	if (vertexArrayObject)
3610 		m_vertexArrays.acquireReference(vertexArrayObject);
3611 
3612 	// Remove old references
3613 	if (m_vertexArrayBinding)
3614 		m_vertexArrays.releaseReference(m_vertexArrayBinding);
3615 
3616 	m_vertexArrayBinding = vertexArrayObject;
3617 }
3618 
3619 void ReferenceContext::genVertexArrays (int numArrays, deUint32* vertexArrays)
3620 {
3621 	RC_IF_ERROR(!vertexArrays, GL_INVALID_VALUE, RC_RET_VOID);
3622 
3623 	for (int ndx = 0; ndx < numArrays; ndx++)
3624 		vertexArrays[ndx] = m_vertexArrays.allocateName();
3625 }
3626 
3627 void ReferenceContext::deleteVertexArrays (int numArrays, const deUint32* vertexArrays)
3628 {
3629 	for (int i = 0; i < numArrays; i++)
3630 	{
3631 		deUint32		name		= vertexArrays[i];
3632 		VertexArray*	vertexArray	= name ? m_vertexArrays.find(name) : DE_NULL;
3633 
3634 		if (vertexArray)
3635 			deleteVertexArray(vertexArray);
3636 	}
3637 }
3638 
3639 void ReferenceContext::vertexAttribPointer (deUint32 index, int rawSize, deUint32 type, deBool normalized, int stride, const void *pointer)
3640 {
3641 	const bool allowBGRA	= !glu::isContextTypeES(getType());
3642 	const int effectiveSize	= (allowBGRA && rawSize == GL_BGRA) ? (4) : (rawSize);
3643 
3644 	RC_IF_ERROR(index >= (deUint32)m_limits.maxVertexAttribs, GL_INVALID_VALUE, RC_RET_VOID);
3645 	RC_IF_ERROR(effectiveSize <= 0 || effectiveSize > 4, GL_INVALID_VALUE, RC_RET_VOID);
3646 	RC_IF_ERROR(type != GL_BYTE					&&	type != GL_UNSIGNED_BYTE	&&
3647 				type != GL_SHORT				&&	type != GL_UNSIGNED_SHORT	&&
3648 				type != GL_INT					&&	type != GL_UNSIGNED_INT		&&
3649 				type != GL_FIXED				&&	type != GL_DOUBLE			&&
3650 				type != GL_FLOAT				&&	type != GL_HALF_FLOAT		&&
3651 				type != GL_INT_2_10_10_10_REV	&&	type != GL_UNSIGNED_INT_2_10_10_10_REV, GL_INVALID_ENUM, RC_RET_VOID);
3652 	RC_IF_ERROR(normalized != GL_TRUE && normalized != GL_FALSE, GL_INVALID_ENUM, RC_RET_VOID);
3653 	RC_IF_ERROR(stride < 0, GL_INVALID_VALUE, RC_RET_VOID);
3654 	RC_IF_ERROR((type == GL_INT_2_10_10_10_REV || type == GL_UNSIGNED_INT_2_10_10_10_REV) && effectiveSize != 4, GL_INVALID_OPERATION, RC_RET_VOID);
3655 	RC_IF_ERROR(m_vertexArrayBinding != DE_NULL && m_arrayBufferBinding == DE_NULL && pointer != DE_NULL, GL_INVALID_OPERATION, RC_RET_VOID);
3656 	RC_IF_ERROR(allowBGRA && rawSize == GL_BGRA && type != GL_INT_2_10_10_10_REV && type != GL_UNSIGNED_INT_2_10_10_10_REV && type != GL_UNSIGNED_BYTE, GL_INVALID_OPERATION, RC_RET_VOID);
3657 	RC_IF_ERROR(allowBGRA && rawSize == GL_BGRA && normalized == GL_FALSE, GL_INVALID_OPERATION, RC_RET_VOID);
3658 
3659 	rc::VertexArray& vao = (m_vertexArrayBinding) ? (*m_vertexArrayBinding) : (m_clientVertexArray);
3660 
3661 	vao.m_arrays[index].size			= rawSize;
3662 	vao.m_arrays[index].stride			= stride;
3663 	vao.m_arrays[index].type			= type;
3664 	vao.m_arrays[index].normalized		= normalized == GL_TRUE;
3665 	vao.m_arrays[index].integer			= false;
3666 	vao.m_arrays[index].pointer			= pointer;
3667 
3668 	// acquire new reference
3669 	if (m_arrayBufferBinding)
3670 		m_buffers.acquireReference(m_arrayBufferBinding);
3671 
3672 	// release old reference
3673 	if (vao.m_arrays[index].bufferBinding)
3674 		m_buffers.releaseReference(vao.m_arrays[index].bufferBinding);
3675 
3676 	vao.m_arrays[index].bufferDeleted	= false;
3677 	vao.m_arrays[index].bufferBinding	= m_arrayBufferBinding;
3678 }
3679 
3680 void ReferenceContext::vertexAttribIPointer (deUint32 index, int size, deUint32 type, int stride, const void *pointer)
3681 {
3682 	RC_IF_ERROR(index >= (deUint32)m_limits.maxVertexAttribs, GL_INVALID_VALUE, RC_RET_VOID);
3683 	RC_IF_ERROR(size <= 0 || size > 4, GL_INVALID_VALUE, RC_RET_VOID);
3684 	RC_IF_ERROR(type != GL_BYTE					&&	type != GL_UNSIGNED_BYTE	&&
3685 				type != GL_SHORT				&&	type != GL_UNSIGNED_SHORT	&&
3686 				type != GL_INT					&&	type != GL_UNSIGNED_INT, GL_INVALID_ENUM, RC_RET_VOID);
3687 	RC_IF_ERROR(stride < 0, GL_INVALID_VALUE, RC_RET_VOID);
3688 	RC_IF_ERROR(m_vertexArrayBinding != DE_NULL && m_arrayBufferBinding == DE_NULL && pointer != DE_NULL, GL_INVALID_OPERATION, RC_RET_VOID);
3689 
3690 	rc::VertexArray& vao = (m_vertexArrayBinding) ? (*m_vertexArrayBinding) : (m_clientVertexArray);
3691 
3692 	vao.m_arrays[index].size			= size;
3693 	vao.m_arrays[index].stride			= stride;
3694 	vao.m_arrays[index].type			= type;
3695 	vao.m_arrays[index].normalized		= false;
3696 	vao.m_arrays[index].integer			= true;
3697 	vao.m_arrays[index].pointer			= pointer;
3698 
3699 	// acquire new reference
3700 	if (m_arrayBufferBinding)
3701 		m_buffers.acquireReference(m_arrayBufferBinding);
3702 
3703 	// release old reference
3704 	if (vao.m_arrays[index].bufferBinding)
3705 		m_buffers.releaseReference(vao.m_arrays[index].bufferBinding);
3706 
3707 	vao.m_arrays[index].bufferDeleted	= false;
3708 	vao.m_arrays[index].bufferBinding	= m_arrayBufferBinding;
3709 }
3710 
3711 void ReferenceContext::enableVertexAttribArray (deUint32 index)
3712 {
3713 	RC_IF_ERROR(index >= (deUint32)m_limits.maxVertexAttribs, GL_INVALID_VALUE, RC_RET_VOID);
3714 
3715 	rc::VertexArray& vao = (m_vertexArrayBinding) ? (*m_vertexArrayBinding) : (m_clientVertexArray);
3716 	vao.m_arrays[index].enabled = true;
3717 }
3718 
3719 void ReferenceContext::disableVertexAttribArray (deUint32 index)
3720 {
3721 	RC_IF_ERROR(index >= (deUint32)m_limits.maxVertexAttribs, GL_INVALID_VALUE, RC_RET_VOID);
3722 
3723 	rc::VertexArray& vao = (m_vertexArrayBinding) ? (*m_vertexArrayBinding) : (m_clientVertexArray);
3724 	vao.m_arrays[index].enabled = false;
3725 }
3726 
3727 void ReferenceContext::vertexAttribDivisor (deUint32 index, deUint32 divisor)
3728 {
3729 	RC_IF_ERROR(index >= (deUint32)m_limits.maxVertexAttribs, GL_INVALID_VALUE, RC_RET_VOID);
3730 
3731 	rc::VertexArray& vao = (m_vertexArrayBinding) ? (*m_vertexArrayBinding) : (m_clientVertexArray);
3732 	vao.m_arrays[index].divisor = divisor;
3733 }
3734 
3735 void ReferenceContext::vertexAttrib1f (deUint32 index, float x)
3736 {
3737 	RC_IF_ERROR(index >= (deUint32)m_limits.maxVertexAttribs, GL_INVALID_VALUE, RC_RET_VOID);
3738 
3739 	m_currentAttribs[index] = rr::GenericVec4(tcu::Vec4(x, 0, 0, 1));
3740 }
3741 
3742 void ReferenceContext::vertexAttrib2f (deUint32 index, float x, float y)
3743 {
3744 	RC_IF_ERROR(index >= (deUint32)m_limits.maxVertexAttribs, GL_INVALID_VALUE, RC_RET_VOID);
3745 
3746 	m_currentAttribs[index] = rr::GenericVec4(tcu::Vec4(x, y, 0, 1));
3747 }
3748 
3749 void ReferenceContext::vertexAttrib3f (deUint32 index, float x, float y, float z)
3750 {
3751 	RC_IF_ERROR(index >= (deUint32)m_limits.maxVertexAttribs, GL_INVALID_VALUE, RC_RET_VOID);
3752 
3753 	m_currentAttribs[index] = rr::GenericVec4(tcu::Vec4(x, y, z, 1));
3754 }
3755 
3756 void ReferenceContext::vertexAttrib4f (deUint32 index, float x, float y, float z, float w)
3757 {
3758 	RC_IF_ERROR(index >= (deUint32)m_limits.maxVertexAttribs, GL_INVALID_VALUE, RC_RET_VOID);
3759 
3760 	m_currentAttribs[index] = rr::GenericVec4(tcu::Vec4(x, y, z, w));
3761 }
3762 
3763 void ReferenceContext::vertexAttribI4i (deUint32 index, deInt32 x, deInt32 y, deInt32 z, deInt32 w)
3764 {
3765 	RC_IF_ERROR(index >= (deUint32)m_limits.maxVertexAttribs, GL_INVALID_VALUE, RC_RET_VOID);
3766 
3767 	m_currentAttribs[index] = rr::GenericVec4(tcu::IVec4(x, y, z, w));
3768 }
3769 
3770 void ReferenceContext::vertexAttribI4ui (deUint32 index, deUint32 x, deUint32 y, deUint32 z, deUint32 w)
3771 {
3772 	RC_IF_ERROR(index >= (deUint32)m_limits.maxVertexAttribs, GL_INVALID_VALUE, RC_RET_VOID);
3773 
3774 	m_currentAttribs[index] = rr::GenericVec4(tcu::UVec4(x, y, z, w));
3775 }
3776 
3777 deInt32 ReferenceContext::getAttribLocation (deUint32 program, const char *name)
3778 {
3779 	ShaderProgramObjectContainer* shaderProg = m_programs.find(program);
3780 
3781 	RC_IF_ERROR(shaderProg == DE_NULL, GL_INVALID_OPERATION, -1);
3782 
3783 	if (name)
3784 	{
3785 		std::string nameString(name);
3786 
3787 		for (size_t ndx = 0; ndx < shaderProg->m_program->m_attributeNames.size(); ++ndx)
3788 			if (shaderProg->m_program->m_attributeNames[ndx] == nameString)
3789 				return (int)ndx;
3790 	}
3791 
3792 	return -1;
3793 }
3794 
3795 void ReferenceContext::uniformv (deInt32 location, glu::DataType type, deInt32 count, const void* v)
3796 {
3797 	RC_IF_ERROR(m_currentProgram == DE_NULL, GL_INVALID_OPERATION, RC_RET_VOID);
3798 
3799 	std::vector<sglr::UniformSlot>& uniforms = m_currentProgram->m_program->m_uniforms;
3800 
3801 	if (location == -1)
3802 		return;
3803 
3804 	RC_IF_ERROR(location < 0 || (size_t)location >= uniforms.size(), GL_INVALID_OPERATION, RC_RET_VOID);
3805 	RC_IF_ERROR(uniforms[location].type != type, GL_INVALID_OPERATION, RC_RET_VOID);
3806 	RC_IF_ERROR(count != 1, GL_INVALID_OPERATION, RC_RET_VOID); // \todo [2013-12-13 pyry] Array uniforms.
3807 
3808 	{
3809 		const int scalarSize = glu::getDataTypeScalarSize(type);
3810 		DE_ASSERT(scalarSize*sizeof(deUint32) <= sizeof(uniforms[location].value));
3811 		deMemcpy(&uniforms[location].value, v, scalarSize*(int)sizeof(deUint32));
3812 	}
3813 }
3814 
3815 void ReferenceContext::uniform1iv (deInt32 location, deInt32 count, const deInt32* v)
3816 {
3817 	RC_IF_ERROR(m_currentProgram == DE_NULL, GL_INVALID_OPERATION, RC_RET_VOID);
3818 
3819 	std::vector<sglr::UniformSlot>& uniforms = m_currentProgram->m_program->m_uniforms;
3820 
3821 	if (location == -1)
3822 		return;
3823 
3824 	RC_IF_ERROR(location < 0 || (size_t)location >= uniforms.size(), GL_INVALID_OPERATION, RC_RET_VOID);
3825 	RC_IF_ERROR(count != 1, GL_INVALID_OPERATION, RC_RET_VOID); // \todo [2013-12-13 pyry] Array uniforms.
3826 
3827 	switch (uniforms[location].type)
3828 	{
3829 		case glu::TYPE_INT:		uniforms[location].value.i = *v;	return;
3830 
3831 		// \note texture unit is stored to value
3832 		case glu::TYPE_SAMPLER_2D:
3833 		case glu::TYPE_UINT_SAMPLER_2D:
3834 		case glu::TYPE_INT_SAMPLER_2D:
3835 		case glu::TYPE_SAMPLER_CUBE:
3836 		case glu::TYPE_UINT_SAMPLER_CUBE:
3837 		case glu::TYPE_INT_SAMPLER_CUBE:
3838 		case glu::TYPE_SAMPLER_2D_ARRAY:
3839 		case glu::TYPE_UINT_SAMPLER_2D_ARRAY:
3840 		case glu::TYPE_INT_SAMPLER_2D_ARRAY:
3841 		case glu::TYPE_SAMPLER_3D:
3842 		case glu::TYPE_UINT_SAMPLER_3D:
3843 		case glu::TYPE_INT_SAMPLER_3D:
3844 		case glu::TYPE_SAMPLER_CUBE_ARRAY:
3845 		case glu::TYPE_UINT_SAMPLER_CUBE_ARRAY:
3846 		case glu::TYPE_INT_SAMPLER_CUBE_ARRAY:
3847 			uniforms[location].value.i = *v;
3848 			return;
3849 
3850 		default:
3851 			setError(GL_INVALID_OPERATION);
3852 			return;
3853 	}
3854 }
3855 
3856 void ReferenceContext::uniform1f (deInt32 location, const float v0)
3857 {
3858 	uniform1fv(location, 1, &v0);
3859 }
3860 
3861 void ReferenceContext::uniform1i (deInt32 location, deInt32 v0)
3862 {
3863 	uniform1iv(location, 1, &v0);
3864 }
3865 
3866 void ReferenceContext::uniform1fv (deInt32 location, deInt32 count, const float* v)
3867 {
3868 	uniformv(location, glu::TYPE_FLOAT, count, v);
3869 }
3870 
3871 void ReferenceContext::uniform2fv (deInt32 location, deInt32 count, const float* v)
3872 {
3873 	uniformv(location, glu::TYPE_FLOAT_VEC2, count, v);
3874 }
3875 
3876 void ReferenceContext::uniform3fv (deInt32 location, deInt32 count, const float* v)
3877 {
3878 	uniformv(location, glu::TYPE_FLOAT_VEC3, count, v);
3879 }
3880 
3881 void ReferenceContext::uniform4fv (deInt32 location, deInt32 count, const float* v)
3882 {
3883 	uniformv(location, glu::TYPE_FLOAT_VEC4, count, v);
3884 }
3885 
3886 void ReferenceContext::uniform2iv (deInt32 location, deInt32 count, const deInt32* v)
3887 {
3888 	uniformv(location, glu::TYPE_INT_VEC2, count, v);
3889 }
3890 
3891 void ReferenceContext::uniform3iv (deInt32 location, deInt32 count, const deInt32* v)
3892 {
3893 	uniformv(location, glu::TYPE_INT_VEC3, count, v);
3894 }
3895 
3896 void ReferenceContext::uniform4iv (deInt32 location, deInt32 count, const deInt32* v)
3897 {
3898 	uniformv(location, glu::TYPE_INT_VEC4, count, v);
3899 }
3900 
3901 void ReferenceContext::uniformMatrix3fv (deInt32 location, deInt32 count, deBool transpose, const float *value)
3902 {
3903 	RC_IF_ERROR(m_currentProgram == DE_NULL, GL_INVALID_OPERATION, RC_RET_VOID);
3904 
3905 	std::vector<sglr::UniformSlot>& uniforms = m_currentProgram->m_program->m_uniforms;
3906 
3907 	if (location == -1)
3908 		return;
3909 
3910 	RC_IF_ERROR(location < 0 || (size_t)location >= uniforms.size(), GL_INVALID_OPERATION, RC_RET_VOID);
3911 
3912 	if (count == 0)
3913 		return;
3914 
3915 	RC_IF_ERROR(transpose != GL_TRUE && transpose != GL_FALSE, GL_INVALID_ENUM, RC_RET_VOID);
3916 
3917 	switch (uniforms[location].type)
3918 	{
3919 		case glu::TYPE_FLOAT_MAT3:
3920 			RC_IF_ERROR(count > 1, GL_INVALID_OPERATION, RC_RET_VOID);
3921 
3922 			if (transpose == GL_FALSE) // input is column major => transpose from column major to internal row major
3923 				for (int row = 0; row < 3; ++row)
3924 				for (int col = 0; col < 3; ++col)
3925 					uniforms[location].value.m3[row*3+col] = value[col*3+row];
3926 			else // input is row major
3927 				for (int row = 0; row < 3; ++row)
3928 				for (int col = 0; col < 3; ++col)
3929 					uniforms[location].value.m3[row*3+col] = value[row*3+col];
3930 
3931 			break;
3932 
3933 		default:
3934 			setError(GL_INVALID_OPERATION);
3935 			return;
3936 	}
3937 }
3938 
3939 void ReferenceContext::uniformMatrix4fv (deInt32 location, deInt32 count, deBool transpose, const float *value)
3940 {
3941 	RC_IF_ERROR(m_currentProgram == DE_NULL, GL_INVALID_OPERATION, RC_RET_VOID);
3942 
3943 	std::vector<sglr::UniformSlot>& uniforms = m_currentProgram->m_program->m_uniforms;
3944 
3945 	if (location == -1)
3946 		return;
3947 
3948 	RC_IF_ERROR(location < 0 || (size_t)location >= uniforms.size(), GL_INVALID_OPERATION, RC_RET_VOID);
3949 
3950 	if (count == 0)
3951 		return;
3952 
3953 	RC_IF_ERROR(transpose != GL_TRUE && transpose != GL_FALSE, GL_INVALID_ENUM, RC_RET_VOID);
3954 
3955 	switch (uniforms[location].type)
3956 	{
3957 		case glu::TYPE_FLOAT_MAT4:
3958 			RC_IF_ERROR(count > 1, GL_INVALID_OPERATION, RC_RET_VOID);
3959 
3960 			if (transpose == GL_FALSE) // input is column major => transpose from column major to internal row major
3961 				for (int row = 0; row < 4; ++row)
3962 				for (int col = 0; col < 4; ++col)
3963 					uniforms[location].value.m4[row*3+col] = value[col*3+row];
3964 			else // input is row major
3965 				for (int row = 0; row < 4; ++row)
3966 				for (int col = 0; col < 4; ++col)
3967 					uniforms[location].value.m4[row*3+col] = value[row*3+col];
3968 
3969 			break;
3970 
3971 		default:
3972 			setError(GL_INVALID_OPERATION);
3973 			return;
3974 	}
3975 }
3976 
3977 deInt32 ReferenceContext::getUniformLocation (deUint32 program, const char *name)
3978 {
3979 	ShaderProgramObjectContainer* shaderProg = m_programs.find(program);
3980 	RC_IF_ERROR(shaderProg == DE_NULL, GL_INVALID_OPERATION, -1);
3981 
3982 	std::vector<sglr::UniformSlot>& uniforms = shaderProg->m_program->m_uniforms;
3983 
3984 	for (size_t i = 0; i < uniforms.size(); ++i)
3985 		if (name && deStringEqual(uniforms[i].name.c_str(), name))
3986 			return (int)i;
3987 
3988 	return -1;
3989 }
3990 
3991 void ReferenceContext::lineWidth (float w)
3992 {
3993 	RC_IF_ERROR(w < 0.0f, GL_INVALID_VALUE, RC_RET_VOID);
3994 	m_lineWidth = w;
3995 }
3996 
3997 void ReferenceContext::deleteVertexArray (rc::VertexArray* vertexArray)
3998 {
3999 	if (m_vertexArrayBinding == vertexArray)
4000 		bindVertexArray(0);
4001 
4002 	if (vertexArray->m_elementArrayBufferBinding)
4003 		m_buffers.releaseReference(vertexArray->m_elementArrayBufferBinding);
4004 
4005 	for (size_t ndx = 0; ndx < vertexArray->m_arrays.size(); ++ndx)
4006 		if (vertexArray->m_arrays[ndx].bufferBinding)
4007 			m_buffers.releaseReference(vertexArray->m_arrays[ndx].bufferBinding);
4008 
4009 	DE_ASSERT(vertexArray->getRefCount() == 1);
4010 	m_vertexArrays.releaseReference(vertexArray);
4011 }
4012 
4013 void ReferenceContext::deleteProgramObject (rc::ShaderProgramObjectContainer* sp)
4014 {
4015 	// Unbinding program will delete it
4016 	if (m_currentProgram == sp && sp->m_deleteFlag)
4017 	{
4018 		useProgram(0);
4019 		return;
4020 	}
4021 
4022 	// Unbinding program will NOT delete it
4023 	if (m_currentProgram == sp)
4024 		useProgram(0);
4025 
4026 	DE_ASSERT(sp->getRefCount() == 1);
4027 	m_programs.releaseReference(sp);
4028 }
4029 
4030 void ReferenceContext::drawArrays (deUint32 mode, int first, int count)
4031 {
4032 	drawArraysInstanced(mode, first, count, 1);
4033 }
4034 
4035 void ReferenceContext::drawArraysInstanced (deUint32 mode, int first, int count, int instanceCount)
4036 {
4037 	// Error conditions
4038 	{
4039 		RC_IF_ERROR(first < 0 || count < 0 || instanceCount < 0, GL_INVALID_VALUE, RC_RET_VOID);
4040 
4041 		if (!predrawErrorChecks(mode))
4042 			return;
4043 	}
4044 
4045 	// All is ok
4046 	{
4047 		const rr::PrimitiveType primitiveType = sglr::rr_util::mapGLPrimitiveType(mode);
4048 
4049 		drawWithReference(rr::PrimitiveList(primitiveType, count, first), instanceCount);
4050 	}
4051 }
4052 
4053 void ReferenceContext::drawElements (deUint32 mode, int count, deUint32 type, const void *indices)
4054 {
4055 	drawElementsInstanced(mode, count, type, indices, 1);
4056 }
4057 
4058 void ReferenceContext::drawElementsBaseVertex (deUint32 mode, int count, deUint32 type, const void *indices, int baseVertex)
4059 {
4060 	drawElementsInstancedBaseVertex(mode, count, type, indices, 1, baseVertex);
4061 }
4062 
4063 void ReferenceContext::drawElementsInstanced (deUint32 mode, int count, deUint32 type, const void *indices, int instanceCount)
4064 {
4065 	drawElementsInstancedBaseVertex(mode, count, type, indices, instanceCount, 0);
4066 }
4067 
4068 void ReferenceContext::drawElementsInstancedBaseVertex (deUint32 mode, int count, deUint32 type, const void *indices, int instanceCount, int baseVertex)
4069 {
4070 	rc::VertexArray& vao = (m_vertexArrayBinding) ? (*m_vertexArrayBinding) : (m_clientVertexArray);
4071 
4072 	// Error conditions
4073 	{
4074 		RC_IF_ERROR(type != GL_UNSIGNED_BYTE &&
4075 					type != GL_UNSIGNED_SHORT &&
4076 					type != GL_UNSIGNED_INT, GL_INVALID_ENUM, RC_RET_VOID);
4077 		RC_IF_ERROR(count < 0 || instanceCount < 0, GL_INVALID_VALUE, RC_RET_VOID);
4078 
4079 		if (!predrawErrorChecks(mode))
4080 			return;
4081 	}
4082 
4083 	// All is ok
4084 	{
4085 		const rr::PrimitiveType primitiveType	= sglr::rr_util::mapGLPrimitiveType(mode);
4086 		const void*				indicesPtr		= (vao.m_elementArrayBufferBinding) ? (vao.m_elementArrayBufferBinding->getData() + reinterpret_cast<uintptr_t>(indices)) : (indices);
4087 
4088 		drawWithReference(rr::PrimitiveList(primitiveType, count, rr::DrawIndices(indicesPtr, sglr::rr_util::mapGLIndexType(type), baseVertex)), instanceCount);
4089 	}
4090 }
4091 
4092 void ReferenceContext::drawRangeElements (deUint32 mode, deUint32 start, deUint32 end, int count, deUint32 type, const void *indices)
4093 {
4094 	RC_IF_ERROR(end < start, GL_INVALID_VALUE, RC_RET_VOID);
4095 
4096 	drawElements(mode, count, type, indices);
4097 }
4098 
4099 void ReferenceContext::drawRangeElementsBaseVertex (deUint32 mode, deUint32 start, deUint32 end, int count, deUint32 type, const void *indices, int baseVertex)
4100 {
4101 	RC_IF_ERROR(end < start, GL_INVALID_VALUE, RC_RET_VOID);
4102 
4103 	drawElementsBaseVertex(mode, count, type, indices, baseVertex);
4104 }
4105 
4106 void ReferenceContext::drawArraysIndirect (deUint32 mode, const void *indirect)
4107 {
4108 	struct DrawArraysIndirectCommand
4109 	{
4110 		deUint32 count;
4111 		deUint32 primCount;
4112 		deUint32 first;
4113 		deUint32 reservedMustBeZero;
4114 	};
4115 
4116 	const DrawArraysIndirectCommand* command;
4117 
4118 	// Check errors
4119 
4120 	if (!predrawErrorChecks(mode))
4121 		return;
4122 
4123 	// Check pointer validity
4124 
4125 	RC_IF_ERROR(m_drawIndirectBufferBinding == DE_NULL, GL_INVALID_OPERATION, RC_RET_VOID);
4126 	RC_IF_ERROR(!deIsAlignedPtr(indirect, 4), GL_INVALID_OPERATION, RC_RET_VOID);
4127 
4128 	// \note watch for overflows, indirect might be close to 0xFFFFFFFF and indirect+something might overflow
4129 	RC_IF_ERROR((size_t)reinterpret_cast<uintptr_t>(indirect)                                     > (size_t)m_drawIndirectBufferBinding->getSize(), GL_INVALID_OPERATION, RC_RET_VOID);
4130 	RC_IF_ERROR((size_t)reinterpret_cast<uintptr_t>(indirect) + sizeof(DrawArraysIndirectCommand) > (size_t)m_drawIndirectBufferBinding->getSize(), GL_INVALID_OPERATION, RC_RET_VOID);
4131 
4132 	// Check values
4133 
4134 	command = (const DrawArraysIndirectCommand*)(m_drawIndirectBufferBinding->getData() + reinterpret_cast<uintptr_t>(indirect));
4135 	RC_IF_ERROR(command->reservedMustBeZero != 0, GL_INVALID_OPERATION, RC_RET_VOID);
4136 
4137 	// draw
4138 	drawArraysInstanced(mode, command->first, command->count, command->primCount);
4139 }
4140 
4141 void ReferenceContext::drawElementsIndirect	(deUint32 mode, deUint32 type, const void *indirect)
4142 {
4143 	struct DrawElementsIndirectCommand
4144 	{
4145 		deUint32 count;
4146 		deUint32 primCount;
4147 		deUint32 firstIndex;
4148 		deInt32  baseVertex;
4149 		deUint32 reservedMustBeZero;
4150 	};
4151 
4152 	const DrawElementsIndirectCommand* command;
4153 
4154 	// Check errors
4155 
4156 	if (!predrawErrorChecks(mode))
4157 		return;
4158 
4159 	RC_IF_ERROR(type != GL_UNSIGNED_BYTE &&
4160 				type != GL_UNSIGNED_SHORT &&
4161 				type != GL_UNSIGNED_INT, GL_INVALID_ENUM, RC_RET_VOID);
4162 
4163 	RC_IF_ERROR(!getBufferBinding(GL_ELEMENT_ARRAY_BUFFER), GL_INVALID_OPERATION, RC_RET_VOID);
4164 
4165 	// Check pointer validity
4166 
4167 	RC_IF_ERROR(m_drawIndirectBufferBinding == DE_NULL, GL_INVALID_OPERATION, RC_RET_VOID);
4168 	RC_IF_ERROR(!deIsAlignedPtr(indirect, 4), GL_INVALID_OPERATION, RC_RET_VOID);
4169 
4170 	// \note watch for overflows, indirect might be close to 0xFFFFFFFF and indirect+something might overflow
4171 	RC_IF_ERROR((size_t)reinterpret_cast<uintptr_t>(indirect)                                       > (size_t)m_drawIndirectBufferBinding->getSize(), GL_INVALID_OPERATION, RC_RET_VOID);
4172 	RC_IF_ERROR((size_t)reinterpret_cast<uintptr_t>(indirect) + sizeof(DrawElementsIndirectCommand) > (size_t)m_drawIndirectBufferBinding->getSize(), GL_INVALID_OPERATION, RC_RET_VOID);
4173 
4174 	// Check values
4175 
4176 	command = (const DrawElementsIndirectCommand*)(m_drawIndirectBufferBinding->getData() + reinterpret_cast<uintptr_t>(indirect));
4177 	RC_IF_ERROR(command->reservedMustBeZero != 0, GL_INVALID_OPERATION, RC_RET_VOID);
4178 
4179 	// Check command error conditions
4180 	RC_IF_ERROR((int)command->count < 0 || (int)command->primCount < 0, GL_INVALID_VALUE, RC_RET_VOID);
4181 
4182 	// Draw
4183 	{
4184 		const size_t			sizeOfType		= (type == GL_UNSIGNED_BYTE) ?  (1) : ((type == GL_UNSIGNED_SHORT) ? (2) : (4));
4185 		const void*				indicesPtr		= glu::BufferOffsetAsPointer(command->firstIndex * sizeOfType);
4186 
4187 		drawElementsInstancedBaseVertex(mode, (int)command->count, type, indicesPtr, (int)command->primCount, command->baseVertex);
4188 	}
4189 }
4190 
4191 void ReferenceContext::multiDrawArrays (deUint32 mode, const int* first, const int* count, int primCount)
4192 {
4193 	DE_UNREF(mode);
4194 	DE_UNREF(first);
4195 	DE_UNREF(count);
4196 	DE_UNREF(primCount);
4197 
4198 	// not supported in gles, prevent accidental use
4199 	DE_ASSERT(false);
4200 }
4201 
4202 void ReferenceContext::multiDrawElements (deUint32 mode, const int* count, deUint32 type, const void** indices, int primCount)
4203 {
4204 	DE_UNREF(mode);
4205 	DE_UNREF(count);
4206 	DE_UNREF(type);
4207 	DE_UNREF(indices);
4208 	DE_UNREF(primCount);
4209 
4210 	// not supported in gles, prevent accidental use
4211 	DE_ASSERT(false);
4212 }
4213 
4214 void ReferenceContext::multiDrawElementsBaseVertex (deUint32 mode, const int* count, deUint32 type, const void** indices, int primCount, const int* baseVertex)
4215 {
4216 	DE_UNREF(mode);
4217 	DE_UNREF(count);
4218 	DE_UNREF(type);
4219 	DE_UNREF(indices);
4220 	DE_UNREF(primCount);
4221 	DE_UNREF(baseVertex);
4222 
4223 	// not supported in gles, prevent accidental use
4224 	DE_ASSERT(false);
4225 }
4226 
4227 bool ReferenceContext::predrawErrorChecks (deUint32 mode)
4228 {
4229 	RC_IF_ERROR(mode != GL_POINTS &&
4230 				mode != GL_LINE_STRIP && mode != GL_LINE_LOOP && mode != GL_LINES &&
4231 				mode != GL_TRIANGLE_STRIP && mode != GL_TRIANGLE_FAN && mode != GL_TRIANGLES &&
4232 				mode != GL_LINES_ADJACENCY && mode != GL_LINE_STRIP_ADJACENCY &&
4233 				mode != GL_TRIANGLES_ADJACENCY && mode != GL_TRIANGLE_STRIP_ADJACENCY,
4234 				GL_INVALID_ENUM, false);
4235 
4236 	// \todo [jarkko] Uncomment following code when the buffer mapping support is added
4237 	//for (size_t ndx = 0; ndx < vao.m_arrays.size(); ++ndx)
4238 	//	if (vao.m_arrays[ndx].enabled && vao.m_arrays[ndx].bufferBinding && vao.m_arrays[ndx].bufferBinding->isMapped)
4239 	//		RC_ERROR_RET(GL_INVALID_OPERATION, RC_RET_VOID);
4240 
4241 	RC_IF_ERROR(checkFramebufferStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE, GL_INVALID_FRAMEBUFFER_OPERATION, false);
4242 
4243 	// Geometry shader checks
4244 	if (m_currentProgram && m_currentProgram->m_program->m_hasGeometryShader)
4245 	{
4246 		RC_IF_ERROR(m_currentProgram->m_program->rr::GeometryShader::getInputType() == rr::GEOMETRYSHADERINPUTTYPE_POINTS && mode != GL_POINTS, GL_INVALID_OPERATION, false);
4247 
4248 		RC_IF_ERROR(m_currentProgram->m_program->rr::GeometryShader::getInputType() == rr::GEOMETRYSHADERINPUTTYPE_LINES &&
4249 			(mode != GL_LINES &&
4250 			 mode != GL_LINE_STRIP &&
4251 			 mode != GL_LINE_LOOP),
4252 			 GL_INVALID_OPERATION, false);
4253 
4254 		RC_IF_ERROR(m_currentProgram->m_program->rr::GeometryShader::getInputType() == rr::GEOMETRYSHADERINPUTTYPE_TRIANGLES &&
4255 			(mode != GL_TRIANGLES &&
4256 			 mode != GL_TRIANGLE_STRIP &&
4257 			 mode != GL_TRIANGLE_FAN),
4258 			 GL_INVALID_OPERATION, false);
4259 
4260 		RC_IF_ERROR(m_currentProgram->m_program->rr::GeometryShader::getInputType() == rr::GEOMETRYSHADERINPUTTYPE_LINES_ADJACENCY &&
4261 			(mode != GL_LINES_ADJACENCY &&
4262 			 mode != GL_LINE_STRIP_ADJACENCY),
4263 			 GL_INVALID_OPERATION, false);
4264 
4265 		RC_IF_ERROR(m_currentProgram->m_program->rr::GeometryShader::getInputType() == rr::GEOMETRYSHADERINPUTTYPE_TRIANGLES_ADJACENCY &&
4266 			(mode != GL_TRIANGLES_ADJACENCY &&
4267 			 mode != GL_TRIANGLE_STRIP_ADJACENCY),
4268 			 GL_INVALID_OPERATION, false);
4269 	}
4270 
4271 	return true;
4272 }
4273 
4274 static rr::PrimitiveType getPrimitiveBaseType (rr::PrimitiveType derivedType)
4275 {
4276 	switch (derivedType)
4277 	{
4278 		case rr::PRIMITIVETYPE_TRIANGLES:
4279 		case rr::PRIMITIVETYPE_TRIANGLE_STRIP:
4280 		case rr::PRIMITIVETYPE_TRIANGLE_FAN:
4281 		case rr::PRIMITIVETYPE_TRIANGLES_ADJACENCY:
4282 		case rr::PRIMITIVETYPE_TRIANGLE_STRIP_ADJACENCY:
4283 			return rr::PRIMITIVETYPE_TRIANGLES;
4284 
4285 		case rr::PRIMITIVETYPE_LINES:
4286 		case rr::PRIMITIVETYPE_LINE_STRIP:
4287 		case rr::PRIMITIVETYPE_LINE_LOOP:
4288 		case rr::PRIMITIVETYPE_LINES_ADJACENCY:
4289 		case rr::PRIMITIVETYPE_LINE_STRIP_ADJACENCY:
4290 			return rr::PRIMITIVETYPE_LINES;
4291 
4292 		case rr::PRIMITIVETYPE_POINTS:
4293 			return rr::PRIMITIVETYPE_POINTS;
4294 
4295 		default:
4296 			DE_ASSERT(false);
4297 			return rr::PRIMITIVETYPE_LAST;
4298 	}
4299 }
4300 
4301 static deUint32 getFixedRestartIndex (rr::IndexType indexType)
4302 {
4303 	switch (indexType)
4304 	{
4305 		case rr::INDEXTYPE_UINT8:		return 0xFF;
4306 		case rr::INDEXTYPE_UINT16:		return 0xFFFF;
4307 		case rr::INDEXTYPE_UINT32:		return 0xFFFFFFFFul;
4308 
4309 		case rr::INDEXTYPE_LAST:
4310 		default:
4311 			DE_ASSERT(false);
4312 			return 0;
4313 	}
4314 }
4315 
4316 void ReferenceContext::drawWithReference (const rr::PrimitiveList& primitives, int instanceCount)
4317 {
4318 	// undefined results
4319 	if (m_currentProgram == DE_NULL)
4320 		return;
4321 
4322 	rr::MultisamplePixelBufferAccess	colorBuf0	= getDrawColorbuffer();
4323 	rr::MultisamplePixelBufferAccess	depthBuf	= getDepthMultisampleAccess(getDrawDepthbuffer());
4324 	rr::MultisamplePixelBufferAccess	stencilBuf	= getStencilMultisampleAccess(getDrawStencilbuffer());
4325 	const bool							hasStencil	= !isEmpty(stencilBuf);
4326 	const int							stencilBits	= (hasStencil) ? (getNumStencilBits(stencilBuf.raw().getFormat())) : (0);
4327 
4328 	const rr::RenderTarget				renderTarget(colorBuf0, depthBuf, stencilBuf);
4329 	const rr::Program					program		(m_currentProgram->m_program->getVertexShader(),
4330 													 m_currentProgram->m_program->getFragmentShader(),
4331 													 (m_currentProgram->m_program->m_hasGeometryShader) ? (m_currentProgram->m_program->getGeometryShader()) : (DE_NULL));
4332 	rr::RenderState						state		((rr::ViewportState)(colorBuf0), m_limits.subpixelBits);
4333 
4334 	const rr::Renderer					referenceRenderer;
4335 	std::vector<rr::VertexAttrib>		vertexAttribs;
4336 
4337 	// Gen state
4338 	{
4339 		const rr::PrimitiveType	baseType							= getPrimitiveBaseType(primitives.getPrimitiveType());
4340 		const bool				polygonOffsetEnabled				= (baseType == rr::PRIMITIVETYPE_TRIANGLES) ? (m_polygonOffsetFillEnabled) : (false);
4341 
4342 		//state.cullMode											= m_cullMode
4343 
4344 		state.fragOps.scissorTestEnabled							= m_scissorEnabled;
4345 		state.fragOps.scissorRectangle								= rr::WindowRectangle(m_scissorBox.x(), m_scissorBox.y(), m_scissorBox.z(), m_scissorBox.w());
4346 
4347 		state.fragOps.numStencilBits								= stencilBits;
4348 		state.fragOps.stencilTestEnabled							= m_stencilTestEnabled;
4349 
4350 		for (int faceType = 0; faceType < rr::FACETYPE_LAST; faceType++)
4351 		{
4352 			state.fragOps.stencilStates[faceType].compMask	= m_stencil[faceType].opMask;
4353 			state.fragOps.stencilStates[faceType].writeMask	= m_stencil[faceType].writeMask;
4354 			state.fragOps.stencilStates[faceType].ref		= m_stencil[faceType].ref;
4355 			state.fragOps.stencilStates[faceType].func		= sglr::rr_util::mapGLTestFunc(m_stencil[faceType].func);
4356 			state.fragOps.stencilStates[faceType].sFail		= sglr::rr_util::mapGLStencilOp(m_stencil[faceType].opStencilFail);
4357 			state.fragOps.stencilStates[faceType].dpFail	= sglr::rr_util::mapGLStencilOp(m_stencil[faceType].opDepthFail);
4358 			state.fragOps.stencilStates[faceType].dpPass	= sglr::rr_util::mapGLStencilOp(m_stencil[faceType].opDepthPass);
4359 		}
4360 
4361 		state.fragOps.depthTestEnabled								= m_depthTestEnabled;
4362 		state.fragOps.depthFunc										= sglr::rr_util::mapGLTestFunc(m_depthFunc);
4363 		state.fragOps.depthMask										= m_depthMask;
4364 
4365 		state.fragOps.blendMode										= m_blendEnabled ? rr::BLENDMODE_STANDARD : rr::BLENDMODE_NONE;
4366 		state.fragOps.blendRGBState.equation						= sglr::rr_util::mapGLBlendEquation(m_blendModeRGB);
4367 		state.fragOps.blendRGBState.srcFunc							= sglr::rr_util::mapGLBlendFunc(m_blendFactorSrcRGB);
4368 		state.fragOps.blendRGBState.dstFunc							= sglr::rr_util::mapGLBlendFunc(m_blendFactorDstRGB);
4369 		state.fragOps.blendAState.equation							= sglr::rr_util::mapGLBlendEquation(m_blendModeAlpha);
4370 		state.fragOps.blendAState.srcFunc							= sglr::rr_util::mapGLBlendFunc(m_blendFactorSrcAlpha);
4371 		state.fragOps.blendAState.dstFunc							= sglr::rr_util::mapGLBlendFunc(m_blendFactorDstAlpha);
4372 		state.fragOps.blendColor									= m_blendColor;
4373 
4374 		state.fragOps.sRGBEnabled									= m_sRGBUpdateEnabled;
4375 
4376 		state.fragOps.colorMask										= m_colorMask;
4377 
4378 		state.fragOps.depthClampEnabled								= m_depthClampEnabled;
4379 
4380 		state.viewport.rect											= rr::WindowRectangle(m_viewport.x(), m_viewport.y(), m_viewport.z(), m_viewport.w());
4381 		state.viewport.zn											= m_depthRangeNear;
4382 		state.viewport.zf											= m_depthRangeFar;
4383 
4384 		//state.point.pointSize										= m_pointSize;
4385 		state.line.lineWidth										= m_lineWidth;
4386 
4387 		state.fragOps.polygonOffsetEnabled							= polygonOffsetEnabled;
4388 		state.fragOps.polygonOffsetFactor							= m_polygonOffsetFactor;
4389 		state.fragOps.polygonOffsetUnits							= m_polygonOffsetUnits;
4390 
4391 		{
4392 			const rr::IndexType indexType = primitives.getIndexType();
4393 
4394 			if (m_primitiveRestartFixedIndex && indexType != rr::INDEXTYPE_LAST)
4395 			{
4396 				state.restart.enabled = true;
4397 				state.restart.restartIndex = getFixedRestartIndex(indexType);
4398 			}
4399 			else if (m_primitiveRestartSettableIndex)
4400 			{
4401 				// \note PRIMITIVE_RESTART is active for non-indexed (DrawArrays) operations too.
4402 				state.restart.enabled = true;
4403 				state.restart.restartIndex = m_primitiveRestartIndex;
4404 			}
4405 			else
4406 			{
4407 				state.restart.enabled = false;
4408 			}
4409 		}
4410 
4411 		state.provokingVertexConvention								= (m_provokingFirstVertexConvention) ? (rr::PROVOKINGVERTEX_FIRST) : (rr::PROVOKINGVERTEX_LAST);
4412 	}
4413 
4414 	// gen attributes
4415 	{
4416 		rc::VertexArray& vao = (m_vertexArrayBinding) ? (*m_vertexArrayBinding) : (m_clientVertexArray);
4417 
4418 		vertexAttribs.resize(vao.m_arrays.size());
4419 		for (size_t ndx = 0; ndx < vao.m_arrays.size(); ++ndx)
4420 		{
4421 			if (!vao.m_arrays[ndx].enabled)
4422 			{
4423 				vertexAttribs[ndx].type = rr::VERTEXATTRIBTYPE_DONT_CARE; // reading with wrong type is allowed, but results are undefined
4424 				vertexAttribs[ndx].generic = m_currentAttribs[ndx];
4425 			}
4426 			else if (vao.m_arrays[ndx].bufferDeleted)
4427 			{
4428 				vertexAttribs[ndx].type = rr::VERTEXATTRIBTYPE_DONT_CARE; // reading from deleted buffer, output zeros
4429 				vertexAttribs[ndx].generic = tcu::Vec4(0, 0, 0, 0);
4430 			}
4431 			else
4432 			{
4433 				vertexAttribs[ndx].type				= (vao.m_arrays[ndx].integer) ?
4434 														(sglr::rr_util::mapGLPureIntegerVertexAttributeType(vao.m_arrays[ndx].type)) :
4435 														(sglr::rr_util::mapGLFloatVertexAttributeType(vao.m_arrays[ndx].type, vao.m_arrays[ndx].normalized, vao.m_arrays[ndx].size, this->getType()));
4436 				vertexAttribs[ndx].size				= sglr::rr_util::mapGLSize(vao.m_arrays[ndx].size);
4437 				vertexAttribs[ndx].stride			= vao.m_arrays[ndx].stride;
4438 				vertexAttribs[ndx].instanceDivisor	= vao.m_arrays[ndx].divisor;
4439 				vertexAttribs[ndx].pointer			= (vao.m_arrays[ndx].bufferBinding) ? (vao.m_arrays[ndx].bufferBinding->getData() + reinterpret_cast<uintptr_t>(vao.m_arrays[ndx].pointer)) : (vao.m_arrays[ndx].pointer);
4440 			}
4441 		}
4442 	}
4443 
4444 	// Set shader samplers
4445 	for (size_t uniformNdx = 0; uniformNdx < m_currentProgram->m_program->m_uniforms.size(); ++uniformNdx)
4446 	{
4447 		const tcu::Sampler::DepthStencilMode	depthStencilMode	= tcu::Sampler::MODE_DEPTH; // \todo[jarkko] support sampler state
4448 		const int								texNdx				= m_currentProgram->m_program->m_uniforms[uniformNdx].value.i;
4449 
4450 		switch (m_currentProgram->m_program->m_uniforms[uniformNdx].type)
4451 		{
4452 			case glu::TYPE_SAMPLER_1D:
4453 			case glu::TYPE_UINT_SAMPLER_1D:
4454 			case glu::TYPE_INT_SAMPLER_1D:
4455 			{
4456 				rc::Texture1D* tex = DE_NULL;
4457 
4458 				if (texNdx >= 0 && (size_t)texNdx < m_textureUnits.size())
4459 					tex = (m_textureUnits[texNdx].tex1DBinding) ? (m_textureUnits[texNdx].tex1DBinding) : (&m_textureUnits[texNdx].default1DTex);
4460 
4461 				if (tex && tex->isComplete())
4462 				{
4463 					tex->updateView(depthStencilMode);
4464 					m_currentProgram->m_program->m_uniforms[uniformNdx].sampler.tex1D = tex;
4465 				}
4466 				else
4467 					m_currentProgram->m_program->m_uniforms[uniformNdx].sampler.tex1D = &m_emptyTex1D;
4468 
4469 				break;
4470 			}
4471 			case glu::TYPE_SAMPLER_2D:
4472 			case glu::TYPE_UINT_SAMPLER_2D:
4473 			case glu::TYPE_INT_SAMPLER_2D:
4474 			{
4475 				rc::Texture2D* tex = DE_NULL;
4476 
4477 				if (texNdx >= 0 && (size_t)texNdx < m_textureUnits.size())
4478 					tex = (m_textureUnits[texNdx].tex2DBinding) ? (m_textureUnits[texNdx].tex2DBinding) : (&m_textureUnits[texNdx].default2DTex);
4479 
4480 				if (tex && tex->isComplete())
4481 				{
4482 					tex->updateView(depthStencilMode);
4483 					m_currentProgram->m_program->m_uniforms[uniformNdx].sampler.tex2D = tex;
4484 				}
4485 				else
4486 					m_currentProgram->m_program->m_uniforms[uniformNdx].sampler.tex2D = &m_emptyTex2D;
4487 
4488 				break;
4489 			}
4490 			case glu::TYPE_SAMPLER_CUBE:
4491 			case glu::TYPE_UINT_SAMPLER_CUBE:
4492 			case glu::TYPE_INT_SAMPLER_CUBE:
4493 			{
4494 				rc::TextureCube* tex = DE_NULL;
4495 
4496 				if (texNdx >= 0 && (size_t)texNdx < m_textureUnits.size())
4497 					tex = (m_textureUnits[texNdx].texCubeBinding) ? (m_textureUnits[texNdx].texCubeBinding) : (&m_textureUnits[texNdx].defaultCubeTex);
4498 
4499 				if (tex && tex->isComplete())
4500 				{
4501 					tex->updateView(depthStencilMode);
4502 					m_currentProgram->m_program->m_uniforms[uniformNdx].sampler.texCube = tex;
4503 				}
4504 				else
4505 					m_currentProgram->m_program->m_uniforms[uniformNdx].sampler.texCube = &m_emptyTexCube;
4506 
4507 				break;
4508 			}
4509 			case glu::TYPE_SAMPLER_2D_ARRAY:
4510 			case glu::TYPE_UINT_SAMPLER_2D_ARRAY:
4511 			case glu::TYPE_INT_SAMPLER_2D_ARRAY:
4512 			{
4513 				rc::Texture2DArray* tex = DE_NULL;
4514 
4515 				if (texNdx >= 0 && (size_t)texNdx < m_textureUnits.size())
4516 					tex = (m_textureUnits[texNdx].tex2DArrayBinding) ? (m_textureUnits[texNdx].tex2DArrayBinding) : (&m_textureUnits[texNdx].default2DArrayTex);
4517 
4518 				if (tex && tex->isComplete())
4519 				{
4520 					tex->updateView(depthStencilMode);
4521 					m_currentProgram->m_program->m_uniforms[uniformNdx].sampler.tex2DArray = tex;
4522 				}
4523 				else
4524 					m_currentProgram->m_program->m_uniforms[uniformNdx].sampler.tex2DArray = &m_emptyTex2DArray;
4525 
4526 				break;
4527 			}
4528 			case glu::TYPE_SAMPLER_3D:
4529 			case glu::TYPE_UINT_SAMPLER_3D:
4530 			case glu::TYPE_INT_SAMPLER_3D:
4531 			{
4532 				rc::Texture3D* tex = DE_NULL;
4533 
4534 				if (texNdx >= 0 && (size_t)texNdx < m_textureUnits.size())
4535 					tex = (m_textureUnits[texNdx].tex3DBinding) ? (m_textureUnits[texNdx].tex3DBinding) : (&m_textureUnits[texNdx].default3DTex);
4536 
4537 				if (tex && tex->isComplete())
4538 				{
4539 					tex->updateView(depthStencilMode);
4540 					m_currentProgram->m_program->m_uniforms[uniformNdx].sampler.tex3D = tex;
4541 				}
4542 				else
4543 					m_currentProgram->m_program->m_uniforms[uniformNdx].sampler.tex3D = &m_emptyTex3D;
4544 
4545 				break;
4546 			}
4547 			case glu::TYPE_SAMPLER_CUBE_ARRAY:
4548 			case glu::TYPE_UINT_SAMPLER_CUBE_ARRAY:
4549 			case glu::TYPE_INT_SAMPLER_CUBE_ARRAY:
4550 			{
4551 				rc::TextureCubeArray* tex = DE_NULL;
4552 
4553 				if (texNdx >= 0 && (size_t)texNdx < m_textureUnits.size())
4554 					tex = (m_textureUnits[texNdx].texCubeArrayBinding) ? (m_textureUnits[texNdx].texCubeArrayBinding) : (&m_textureUnits[texNdx].defaultCubeArrayTex);
4555 
4556 				if (tex && tex->isComplete())
4557 				{
4558 					tex->updateView(depthStencilMode);
4559 					m_currentProgram->m_program->m_uniforms[uniformNdx].sampler.texCubeArray = tex;
4560 				}
4561 				else
4562 					m_currentProgram->m_program->m_uniforms[uniformNdx].sampler.texCubeArray = &m_emptyTexCubeArray;
4563 
4564 				break;
4565 			}
4566 			default:
4567 				// nothing
4568 				break;
4569 		}
4570 	}
4571 
4572 	referenceRenderer.drawInstanced(rr::DrawCommand(state, renderTarget, program, (int)vertexAttribs.size(), &vertexAttribs[0], primitives), instanceCount);
4573 }
4574 
4575 deUint32 ReferenceContext::createProgram (ShaderProgram* program)
4576 {
4577 	int name = m_programs.allocateName();
4578 
4579 	m_programs.insert(new rc::ShaderProgramObjectContainer(name, program));
4580 
4581 	return name;
4582 }
4583 
4584 void ReferenceContext::useProgram (deUint32 program)
4585 {
4586 	rc::ShaderProgramObjectContainer* shaderProg			= DE_NULL;
4587 	rc::ShaderProgramObjectContainer* programToBeDeleted	= DE_NULL;
4588 
4589 	if (program)
4590 	{
4591 		shaderProg = m_programs.find(program);
4592 
4593 		// shader has not been linked
4594 		if (!shaderProg || shaderProg->m_deleteFlag)
4595 			RC_ERROR_RET(GL_INVALID_OPERATION, RC_RET_VOID);
4596 	}
4597 
4598 	if (m_currentProgram && m_currentProgram->m_deleteFlag)
4599 		programToBeDeleted = m_currentProgram;
4600 
4601 	m_currentProgram = shaderProg;
4602 
4603 	if (programToBeDeleted)
4604 	{
4605 		DE_ASSERT(programToBeDeleted->getRefCount() == 1);
4606 		deleteProgramObject(programToBeDeleted);
4607 	}
4608 }
4609 
4610 void ReferenceContext::deleteProgram (deUint32 program)
4611 {
4612 	if (!program)
4613 		return;
4614 
4615 	rc::ShaderProgramObjectContainer* shaderProg = m_programs.find(program);
4616 	if (shaderProg)
4617 	{
4618 		if (shaderProg == m_currentProgram)
4619 		{
4620 			m_currentProgram->m_deleteFlag = true;
4621 		}
4622 		else
4623 		{
4624 			DE_ASSERT(shaderProg->getRefCount() == 1);
4625 			m_programs.releaseReference(shaderProg);
4626 		}
4627 	}
4628 }
4629 
4630 void ReferenceContext::readPixels (int x, int y, int width, int height, deUint32 format, deUint32 type, void* data)
4631 {
4632 	rr::MultisamplePixelBufferAccess	src = getReadColorbuffer();
4633 	TextureFormat						transferFmt;
4634 
4635 	// Map transfer format.
4636 	transferFmt = glu::mapGLTransferFormat(format, type);
4637 	RC_IF_ERROR(transferFmt.order	== TextureFormat::CHANNELORDER_LAST ||
4638 				transferFmt.type	== TextureFormat::CHANNELTYPE_LAST, GL_INVALID_ENUM, RC_RET_VOID);
4639 
4640 	// Clamp input values
4641 	const int copyX			= deClamp32(x,		0, src.raw().getHeight());
4642 	const int copyY			= deClamp32(y,		0, src.raw().getDepth());
4643 	const int copyWidth		= deClamp32(width,	0, src.raw().getHeight()-x);
4644 	const int copyHeight	= deClamp32(height,	0, src.raw().getDepth()-y);
4645 
4646 	PixelBufferAccess dst(transferFmt, width, height, 1, deAlign32(width*transferFmt.getPixelSize(), m_pixelPackAlignment), 0, getPixelPackPtr(data));
4647 	rr::resolveMultisampleColorBuffer(tcu::getSubregion(dst, 0, 0, copyWidth, copyHeight), rr::getSubregion(src, copyX, copyY, copyWidth, copyHeight));
4648 }
4649 
4650 deUint32 ReferenceContext::getError (void)
4651 {
4652 	deUint32 err = m_lastError;
4653 	m_lastError = GL_NO_ERROR;
4654 	return err;
4655 }
4656 
4657 void ReferenceContext::finish (void)
4658 {
4659 }
4660 
4661 inline void ReferenceContext::setError (deUint32 error)
4662 {
4663 	if (m_lastError == GL_NO_ERROR)
4664 		m_lastError = error;
4665 }
4666 
4667 void ReferenceContext::getIntegerv (deUint32 pname, int* param)
4668 {
4669 	switch (pname)
4670 	{
4671 		case GL_MAX_TEXTURE_SIZE:			*param = m_limits.maxTexture2DSize;			break;
4672 		case GL_MAX_CUBE_MAP_TEXTURE_SIZE:	*param = m_limits.maxTextureCubeSize;		break;
4673 		case GL_MAX_ARRAY_TEXTURE_LAYERS:	*param = m_limits.maxTexture2DArrayLayers;	break;
4674 		case GL_MAX_3D_TEXTURE_SIZE:		*param = m_limits.maxTexture3DSize;			break;
4675 		case GL_MAX_RENDERBUFFER_SIZE:		*param = m_limits.maxRenderbufferSize;		break;
4676 		case GL_MAX_TEXTURE_IMAGE_UNITS:	*param = m_limits.maxTextureImageUnits;		break;
4677 		case GL_MAX_VERTEX_ATTRIBS:			*param = m_limits.maxVertexAttribs;			break;
4678 
4679 		default:
4680 			setError(GL_INVALID_ENUM);
4681 			break;
4682 	}
4683 }
4684 
4685 const char* ReferenceContext::getString (deUint32 pname)
4686 {
4687 	switch (pname)
4688 	{
4689 		case GL_EXTENSIONS:		return m_limits.extensionStr.c_str();
4690 
4691 		default:
4692 			setError(GL_INVALID_ENUM);
4693 			return DE_NULL;
4694 	}
4695 }
4696 
4697 namespace rc
4698 {
4699 
4700 TextureLevelArray::TextureLevelArray (void)
4701 {
4702 }
4703 
4704 TextureLevelArray::~TextureLevelArray (void)
4705 {
4706 	clear();
4707 }
4708 
4709 void TextureLevelArray::clear (void)
4710 {
4711 	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(m_data) == DE_LENGTH_OF_ARRAY(m_access));
4712 
4713 	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(m_data); ndx++)
4714 	{
4715 		m_data[ndx].clear();
4716 		m_access[ndx] = PixelBufferAccess();
4717 	}
4718 }
4719 
4720 void TextureLevelArray::allocLevel (int level, const tcu::TextureFormat& format, int width, int height, int depth)
4721 {
4722 	const int dataSize = format.getPixelSize()*width*height*depth;
4723 
4724 	DE_ASSERT(deInBounds32(level, 0, DE_LENGTH_OF_ARRAY(m_data)));
4725 
4726 	if (hasLevel(level))
4727 		clearLevel(level);
4728 
4729 	m_data[level].setStorage(dataSize);
4730 	m_access[level] = PixelBufferAccess(format, width, height, depth, m_data[level].getPtr());
4731 }
4732 
4733 void TextureLevelArray::clearLevel (int level)
4734 {
4735 	DE_ASSERT(deInBounds32(level, 0, DE_LENGTH_OF_ARRAY(m_data)));
4736 
4737 	m_data[level].clear();
4738 	m_access[level] = PixelBufferAccess();
4739 }
4740 
4741 void TextureLevelArray::updateSamplerMode (tcu::Sampler::DepthStencilMode mode)
4742 {
4743 	for (int levelNdx = 0; hasLevel(levelNdx); ++levelNdx)
4744 		m_effectiveAccess[levelNdx] = tcu::getEffectiveDepthStencilAccess(m_access[levelNdx], mode);
4745 }
4746 
4747 Texture::Texture (deUint32 name, Type type, deBool seamless)
4748 	: NamedObject	(name)
4749 	, m_type		(type)
4750 	, m_immutable	(false)
4751 	, m_sampler		(tcu::Sampler::REPEAT_GL,
4752 					 tcu::Sampler::REPEAT_GL,
4753 					 tcu::Sampler::REPEAT_GL,
4754 					 tcu::Sampler::NEAREST_MIPMAP_LINEAR,
4755 					 tcu::Sampler::LINEAR,
4756 					 0.0f,				// LOD threshold
4757 					 true,				// normalized coords
4758 					 tcu::Sampler::COMPAREMODE_NONE,
4759 					 0,					// cmp channel ndx
4760 					 tcu::Vec4(0.0f),	// border color
4761 					 seamless			// seamless cube map, Default value is True.
4762 					 )
4763 	, m_baseLevel	(0)
4764 	, m_maxLevel	(1000)
4765 {
4766 }
4767 
4768 Texture1D::Texture1D (deUint32 name)
4769 	: Texture	(name, TYPE_1D)
4770 	, m_view	(0, DE_NULL)
4771 {
4772 }
4773 
4774 Texture1D::~Texture1D (void)
4775 {
4776 }
4777 
4778 void Texture1D::allocLevel (int level, const tcu::TextureFormat& format, int width)
4779 {
4780 	m_levels.allocLevel(level, format, width, 1, 1);
4781 }
4782 
4783 bool Texture1D::isComplete (void) const
4784 {
4785 	const int	baseLevel	= getBaseLevel();
4786 
4787 	if (hasLevel(baseLevel))
4788 	{
4789 		const tcu::ConstPixelBufferAccess&	level0		= getLevel(baseLevel);
4790 		const bool							mipmap		= isMipmapFilter(getSampler().minFilter);
4791 
4792 		if (mipmap)
4793 		{
4794 			const TextureFormat&	format		= level0.getFormat();
4795 			const int				w			= level0.getWidth();
4796 			const int				numLevels	= de::min(getMaxLevel()-baseLevel+1, getNumMipLevels1D(w));
4797 
4798 			for (int levelNdx = 1; levelNdx < numLevels; levelNdx++)
4799 			{
4800 				if (hasLevel(baseLevel+levelNdx))
4801 				{
4802 					const tcu::ConstPixelBufferAccess&	level		= getLevel(baseLevel+levelNdx);
4803 					const int							expectedW	= getMipLevelSize(w, levelNdx);
4804 
4805 					if (level.getWidth()	!= expectedW	||
4806 						level.getFormat()	!= format)
4807 						return false;
4808 				}
4809 				else
4810 					return false;
4811 			}
4812 		}
4813 
4814 		return true;
4815 	}
4816 	else
4817 		return false;
4818 }
4819 
4820 tcu::Vec4 Texture1D::sample (float s, float lod) const
4821 {
4822 	return m_view.sample(getSampler(), s, 0.0f, lod);
4823 }
4824 
4825 void Texture1D::sample4 (tcu::Vec4 output[4], const float packetTexcoords[4], float lodBias) const
4826 {
4827 	const float texWidth = (float)m_view.getWidth();
4828 
4829 	const float dFdx0 = packetTexcoords[1] - packetTexcoords[0];
4830 	const float dFdx1 = packetTexcoords[3] - packetTexcoords[2];
4831 	const float dFdy0 = packetTexcoords[2] - packetTexcoords[0];
4832 	const float dFdy1 = packetTexcoords[3] - packetTexcoords[1];
4833 
4834 	for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
4835 	{
4836 		const float& dFdx = (fragNdx > 2) ? dFdx1 : dFdx0;
4837 		const float& dFdy = (fragNdx % 2) ? dFdy1 : dFdy0;
4838 
4839 		const float mu = de::max(de::abs(dFdx), de::abs(dFdy));
4840 		const float p = mu * texWidth;
4841 
4842 		const float	lod = deFloatLog2(p) + lodBias;
4843 
4844 		output[fragNdx] = sample(packetTexcoords[fragNdx], lod);
4845 	}
4846 }
4847 
4848 void Texture1D::updateView (tcu::Sampler::DepthStencilMode mode)
4849 {
4850 	const int baseLevel	= getBaseLevel();
4851 
4852 	if (hasLevel(baseLevel) && !isEmpty(getLevel(baseLevel)))
4853 	{
4854 		const int	width		= getLevel(baseLevel).getWidth();
4855 		const bool	isMipmap	= isMipmapFilter(getSampler().minFilter);
4856 		const int	numLevels	= isMipmap ? de::min(getMaxLevel()-baseLevel+1, getNumMipLevels1D(width)) : 1;
4857 
4858 		m_levels.updateSamplerMode(mode);
4859 		m_view = tcu::Texture2DView(numLevels, m_levels.getEffectiveLevels() + baseLevel);
4860 	}
4861 	else
4862 		m_view = tcu::Texture2DView(0, DE_NULL);
4863 }
4864 
4865 Texture2D::Texture2D (deUint32 name, bool es2)
4866 	: Texture	(name, TYPE_2D)
4867 	, m_view	(0, DE_NULL, es2)
4868 {
4869 }
4870 
4871 Texture2D::~Texture2D (void)
4872 {
4873 }
4874 
4875 void Texture2D::allocLevel (int level, const tcu::TextureFormat& format, int width, int height)
4876 {
4877 	m_levels.allocLevel(level, format, width, height, 1);
4878 }
4879 
4880 bool Texture2D::isComplete (void) const
4881 {
4882 	const int	baseLevel	= getBaseLevel();
4883 
4884 	if (hasLevel(baseLevel))
4885 	{
4886 		const tcu::ConstPixelBufferAccess&	level0		= getLevel(baseLevel);
4887 		const bool							mipmap		= isMipmapFilter(getSampler().minFilter);
4888 
4889 		if (mipmap)
4890 		{
4891 			const TextureFormat&	format		= level0.getFormat();
4892 			const int				w			= level0.getWidth();
4893 			const int				h			= level0.getHeight();
4894 			const int				numLevels	= de::min(getMaxLevel()-baseLevel+1, getNumMipLevels2D(w, h));
4895 
4896 			for (int levelNdx = 1; levelNdx < numLevels; levelNdx++)
4897 			{
4898 				if (hasLevel(baseLevel+levelNdx))
4899 				{
4900 					const tcu::ConstPixelBufferAccess&	level		= getLevel(baseLevel+levelNdx);
4901 					const int							expectedW	= getMipLevelSize(w, levelNdx);
4902 					const int							expectedH	= getMipLevelSize(h, levelNdx);
4903 
4904 					if (level.getWidth()	!= expectedW	||
4905 						level.getHeight()	!= expectedH	||
4906 						level.getFormat()	!= format)
4907 						return false;
4908 				}
4909 				else
4910 					return false;
4911 			}
4912 		}
4913 
4914 		return true;
4915 	}
4916 	else
4917 		return false;
4918 }
4919 
4920 void Texture2D::updateView (tcu::Sampler::DepthStencilMode mode)
4921 {
4922 	const int baseLevel	= getBaseLevel();
4923 
4924 	if (hasLevel(baseLevel) && !isEmpty(getLevel(baseLevel)))
4925 	{
4926 		// Update number of levels in mipmap pyramid.
4927 		const int	width		= getLevel(baseLevel).getWidth();
4928 		const int	height		= getLevel(baseLevel).getHeight();
4929 		const bool	isMipmap	= isMipmapFilter(getSampler().minFilter);
4930 		const int	numLevels	= isMipmap ? de::min(getMaxLevel()-baseLevel+1, getNumMipLevels2D(width, height)) : 1;
4931 
4932 		m_levels.updateSamplerMode(mode);
4933 		m_view = tcu::Texture2DView(numLevels, m_levels.getEffectiveLevels() + baseLevel);
4934 	}
4935 	else
4936 		m_view = tcu::Texture2DView(0, DE_NULL);
4937 }
4938 
4939 tcu::Vec4 Texture2D::sample (float s, float t, float lod) const
4940 {
4941 	return m_view.sample(getSampler(), s, t, lod);
4942 }
4943 
4944 void Texture2D::sample4 (tcu::Vec4 output[4], const tcu::Vec2 packetTexcoords[4], float lodBias) const
4945 {
4946 	const float texWidth  = (float)m_view.getWidth();
4947 	const float texHeight = (float)m_view.getHeight();
4948 
4949 	const tcu::Vec2 dFdx0 = packetTexcoords[1] - packetTexcoords[0];
4950 	const tcu::Vec2 dFdx1 = packetTexcoords[3] - packetTexcoords[2];
4951 	const tcu::Vec2 dFdy0 = packetTexcoords[2] - packetTexcoords[0];
4952 	const tcu::Vec2 dFdy1 = packetTexcoords[3] - packetTexcoords[1];
4953 
4954 	for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
4955 	{
4956 		const tcu::Vec2& dFdx = (fragNdx & 2) ? dFdx1 : dFdx0;
4957 		const tcu::Vec2& dFdy = (fragNdx & 1) ? dFdy1 : dFdy0;
4958 
4959 		const float mu = de::max(de::abs(dFdx.x()), de::abs(dFdy.x()));
4960 		const float mv = de::max(de::abs(dFdx.y()), de::abs(dFdy.y()));
4961 		const float p = de::max(mu * texWidth, mv * texHeight);
4962 
4963 		const float	lod = deFloatLog2(p) + lodBias;
4964 
4965 		output[fragNdx] = sample(packetTexcoords[fragNdx].x(), packetTexcoords[fragNdx].y(), lod);
4966 	}
4967 }
4968 
4969 TextureCube::TextureCube (deUint32 name, deBool seamless)
4970 	: Texture(name, TYPE_CUBE_MAP, seamless)
4971 {
4972 }
4973 
4974 TextureCube::~TextureCube (void)
4975 {
4976 }
4977 
4978 void TextureCube::clearLevels (void)
4979 {
4980 	for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
4981 		m_levels[face].clear();
4982 }
4983 
4984 void TextureCube::allocFace (int level, tcu::CubeFace face, const tcu::TextureFormat& format, int width, int height)
4985 {
4986 	m_levels[face].allocLevel(level, format, width, height, 1);
4987 }
4988 
4989 bool TextureCube::isComplete (void) const
4990 {
4991 	const int	baseLevel	= getBaseLevel();
4992 
4993 	if (hasFace(baseLevel, tcu::CUBEFACE_NEGATIVE_X))
4994 	{
4995 		const int					width		= getFace(baseLevel, tcu::CUBEFACE_NEGATIVE_X).getWidth();
4996 		const int					height		= getFace(baseLevel, tcu::CUBEFACE_NEGATIVE_X).getHeight();
4997 		const tcu::TextureFormat&	format		= getFace(baseLevel, tcu::CUBEFACE_NEGATIVE_X).getFormat();
4998 		const bool					mipmap		= isMipmapFilter(getSampler().minFilter);
4999 		const int					numLevels	= mipmap ? de::min(getMaxLevel()-baseLevel+1, getNumMipLevels2D(width, height)) : 1;
5000 
5001 		if (width != height)
5002 			return false; // Non-square is not supported.
5003 
5004 		// \note Level 0 is always checked for consistency
5005 		for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
5006 		{
5007 			const int levelW	= getMipLevelSize(width,	levelNdx);
5008 			const int levelH	= getMipLevelSize(height,	levelNdx);
5009 
5010 			for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
5011 			{
5012 				if (hasFace(baseLevel+levelNdx, (tcu::CubeFace)face))
5013 				{
5014 					const tcu::ConstPixelBufferAccess& level = getFace(baseLevel+levelNdx, (tcu::CubeFace)face);
5015 
5016 					if (level.getWidth()	!= levelW	||
5017 						level.getHeight()	!= levelH	||
5018 						level.getFormat()	!= format)
5019 						return false;
5020 				}
5021 				else
5022 					return false;
5023 			}
5024 		}
5025 
5026 		return true;
5027 	}
5028 	else
5029 		return false;
5030 }
5031 
5032 void TextureCube::updateView (tcu::Sampler::DepthStencilMode mode)
5033 {
5034 	const int							baseLevel	= getBaseLevel();
5035 	const tcu::ConstPixelBufferAccess*	faces[tcu::CUBEFACE_LAST];
5036 
5037 	deMemset(&faces[0], 0, sizeof(faces));
5038 
5039 	if (isComplete())
5040 	{
5041 		const int	size		= getFace(baseLevel, tcu::CUBEFACE_NEGATIVE_X).getWidth();
5042 		const bool	isMipmap	= isMipmapFilter(getSampler().minFilter);
5043 		const int	numLevels	= isMipmap ? de::min(getMaxLevel()-baseLevel+1, getNumMipLevels1D(size)) : 1;
5044 
5045 		for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
5046 		{
5047 			m_levels[face].updateSamplerMode(mode);
5048 			faces[face] = m_levels[face].getEffectiveLevels() + baseLevel;
5049 		}
5050 
5051 		m_view = tcu::TextureCubeView(numLevels, faces);
5052 	}
5053 	else
5054 		m_view = tcu::TextureCubeView(0, faces);
5055 }
5056 
5057 tcu::Vec4 TextureCube::sample (float s, float t, float p, float lod) const
5058 {
5059 	return m_view.sample(getSampler(), s, t, p, lod);
5060 }
5061 
5062 void TextureCube::sample4 (tcu::Vec4 output[4], const tcu::Vec3 packetTexcoords[4], float lodBias) const
5063 {
5064 	const float cubeSide = (float)m_view.getSize();
5065 
5066 	// Each tex coord might be in a different face.
5067 
5068 	for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
5069 	{
5070 		const tcu::CubeFace face		= tcu::selectCubeFace(packetTexcoords[fragNdx]);
5071 		const tcu::Vec2		coords[4]	=
5072 		{
5073 			tcu::projectToFace(face, packetTexcoords[0]),
5074 			tcu::projectToFace(face, packetTexcoords[1]),
5075 			tcu::projectToFace(face, packetTexcoords[2]),
5076 			tcu::projectToFace(face, packetTexcoords[3]),
5077 		};
5078 
5079 		const tcu::Vec2 dFdx0 = coords[1] - coords[0];
5080 		const tcu::Vec2 dFdx1 = coords[3] - coords[2];
5081 		const tcu::Vec2 dFdy0 = coords[2] - coords[0];
5082 		const tcu::Vec2 dFdy1 = coords[3] - coords[1];
5083 
5084 		const tcu::Vec2& dFdx = (fragNdx & 2) ? dFdx1 : dFdx0;
5085 		const tcu::Vec2& dFdy = (fragNdx & 1) ? dFdy1 : dFdy0;
5086 
5087 		const float mu = de::max(de::abs(dFdx.x()), de::abs(dFdy.x()));
5088 		const float mv = de::max(de::abs(dFdx.y()), de::abs(dFdy.y()));
5089 		const float p = de::max(mu * cubeSide, mv * cubeSide);
5090 
5091 		const float	lod = deFloatLog2(p) + lodBias;
5092 
5093 		output[fragNdx] = sample(packetTexcoords[fragNdx].x(), packetTexcoords[fragNdx].y(), packetTexcoords[fragNdx].z(), lod);
5094 	}
5095 }
5096 
5097 Texture2DArray::Texture2DArray (deUint32 name)
5098 	: Texture	(name, TYPE_2D_ARRAY)
5099 	, m_view	(0, DE_NULL)
5100 {
5101 }
5102 
5103 Texture2DArray::~Texture2DArray (void)
5104 {
5105 }
5106 
5107 void Texture2DArray::allocLevel (int level, const tcu::TextureFormat& format, int width, int height, int numLayers)
5108 {
5109 	m_levels.allocLevel(level, format, width, height, numLayers);
5110 }
5111 
5112 bool Texture2DArray::isComplete (void) const
5113 {
5114 	const int	baseLevel	= getBaseLevel();
5115 
5116 	if (hasLevel(baseLevel))
5117 	{
5118 		const tcu::ConstPixelBufferAccess&	level0		= getLevel(baseLevel);
5119 		const bool							mipmap		= isMipmapFilter(getSampler().minFilter);
5120 
5121 		if (mipmap)
5122 		{
5123 			const TextureFormat&	format		= level0.getFormat();
5124 			const int				w			= level0.getWidth();
5125 			const int				h			= level0.getHeight();
5126 			const int				numLayers	= level0.getDepth();
5127 			const int				numLevels	= de::min(getMaxLevel()-baseLevel+1, getNumMipLevels2D(w, h));
5128 
5129 			for (int levelNdx = 1; levelNdx < numLevels; levelNdx++)
5130 			{
5131 				if (hasLevel(baseLevel+levelNdx))
5132 				{
5133 					const tcu::ConstPixelBufferAccess&	level		= getLevel(baseLevel+levelNdx);
5134 					const int							expectedW	= getMipLevelSize(w, levelNdx);
5135 					const int							expectedH	= getMipLevelSize(h, levelNdx);
5136 
5137 					if (level.getWidth()	!= expectedW	||
5138 						level.getHeight()	!= expectedH	||
5139 						level.getDepth()	!= numLayers	||
5140 						level.getFormat()	!= format)
5141 						return false;
5142 				}
5143 				else
5144 					return false;
5145 			}
5146 		}
5147 
5148 		return true;
5149 	}
5150 	else
5151 		return false;
5152 }
5153 
5154 void Texture2DArray::updateView (tcu::Sampler::DepthStencilMode mode)
5155 {
5156 	const int baseLevel	= getBaseLevel();
5157 
5158 	if (hasLevel(baseLevel) && !isEmpty(getLevel(baseLevel)))
5159 	{
5160 		const int	width		= getLevel(baseLevel).getWidth();
5161 		const int	height		= getLevel(baseLevel).getHeight();
5162 		const bool	isMipmap	= isMipmapFilter(getSampler().minFilter);
5163 		const int	numLevels	= isMipmap ? de::min(getMaxLevel()-baseLevel+1, getNumMipLevels2D(width, height)) : 1;
5164 
5165 		m_levels.updateSamplerMode(mode);
5166 		m_view = tcu::Texture2DArrayView(numLevels, m_levels.getEffectiveLevels() + baseLevel);
5167 	}
5168 	else
5169 		m_view = tcu::Texture2DArrayView(0, DE_NULL);
5170 }
5171 
5172 tcu::Vec4 Texture2DArray::sample (float s, float t, float r, float lod) const
5173 {
5174 	return m_view.sample(getSampler(), s, t, r, lod);
5175 }
5176 
5177 void Texture2DArray::sample4 (tcu::Vec4 output[4], const tcu::Vec3 packetTexcoords[4], float lodBias) const
5178 {
5179 	const float texWidth  = (float)m_view.getWidth();
5180 	const float texHeight = (float)m_view.getHeight();
5181 
5182 	const tcu::Vec3 dFdx0 = packetTexcoords[1] - packetTexcoords[0];
5183 	const tcu::Vec3 dFdx1 = packetTexcoords[3] - packetTexcoords[2];
5184 	const tcu::Vec3 dFdy0 = packetTexcoords[2] - packetTexcoords[0];
5185 	const tcu::Vec3 dFdy1 = packetTexcoords[3] - packetTexcoords[1];
5186 
5187 	for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
5188 	{
5189 		const tcu::Vec3& dFdx = (fragNdx & 2) ? dFdx1 : dFdx0;
5190 		const tcu::Vec3& dFdy = (fragNdx & 1) ? dFdy1 : dFdy0;
5191 
5192 		const float mu = de::max(de::abs(dFdx.x()), de::abs(dFdy.x()));
5193 		const float mv = de::max(de::abs(dFdx.y()), de::abs(dFdy.y()));
5194 		const float p = de::max(mu * texWidth, mv * texHeight);
5195 
5196 		const float	lod = deFloatLog2(p) + lodBias;
5197 
5198 		output[fragNdx] = sample(packetTexcoords[fragNdx].x(), packetTexcoords[fragNdx].y(), packetTexcoords[fragNdx].z(), lod);
5199 	}
5200 }
5201 
5202 TextureCubeArray::TextureCubeArray (deUint32 name)
5203 	: Texture	(name, TYPE_CUBE_MAP_ARRAY)
5204 	, m_view	(0, DE_NULL)
5205 {
5206 }
5207 
5208 TextureCubeArray::~TextureCubeArray (void)
5209 {
5210 }
5211 
5212 void TextureCubeArray::allocLevel (int level, const tcu::TextureFormat& format, int width, int height, int numLayers)
5213 {
5214 	DE_ASSERT(numLayers % 6 == 0);
5215 	m_levels.allocLevel(level, format, width, height, numLayers);
5216 }
5217 
5218 bool TextureCubeArray::isComplete (void) const
5219 {
5220 	const int	baseLevel	= getBaseLevel();
5221 
5222 	if (hasLevel(baseLevel))
5223 	{
5224 		const tcu::ConstPixelBufferAccess&	level0		= getLevel(baseLevel);
5225 		const bool							mipmap		= isMipmapFilter(getSampler().minFilter);
5226 
5227 		if (mipmap)
5228 		{
5229 			const TextureFormat&	format		= level0.getFormat();
5230 			const int				w			= level0.getWidth();
5231 			const int				h			= level0.getHeight();
5232 			const int				numLayers	= level0.getDepth();
5233 			const int				numLevels	= de::min(getMaxLevel()-baseLevel+1, getNumMipLevels2D(w, h));
5234 
5235 			for (int levelNdx = 1; levelNdx < numLevels; levelNdx++)
5236 			{
5237 				if (hasLevel(baseLevel+levelNdx))
5238 				{
5239 					const tcu::ConstPixelBufferAccess&	level		= getLevel(baseLevel+levelNdx);
5240 					const int							expectedW	= getMipLevelSize(w, levelNdx);
5241 					const int							expectedH	= getMipLevelSize(h, levelNdx);
5242 
5243 					if (level.getWidth()	!= expectedW	||
5244 						level.getHeight()	!= expectedH	||
5245 						level.getDepth()	!= numLayers	||
5246 						level.getFormat()	!= format)
5247 						return false;
5248 				}
5249 				else
5250 					return false;
5251 			}
5252 		}
5253 
5254 		return true;
5255 	}
5256 	else
5257 		return false;
5258 }
5259 
5260 void TextureCubeArray::updateView (tcu::Sampler::DepthStencilMode mode)
5261 {
5262 	const int baseLevel	= getBaseLevel();
5263 
5264 	if (hasLevel(baseLevel) && !isEmpty(getLevel(baseLevel)))
5265 	{
5266 		const int	width		= getLevel(baseLevel).getWidth();
5267 		const int	height		= getLevel(baseLevel).getHeight();
5268 		const bool	isMipmap	= isMipmapFilter(getSampler().minFilter);
5269 		const int	numLevels	= isMipmap ? de::min(getMaxLevel()-baseLevel+1, getNumMipLevels2D(width, height)) : 1;
5270 
5271 		m_levels.updateSamplerMode(mode);
5272 		m_view = tcu::TextureCubeArrayView(numLevels, m_levels.getEffectiveLevels() + baseLevel);
5273 	}
5274 	else
5275 		m_view = tcu::TextureCubeArrayView(0, DE_NULL);
5276 }
5277 
5278 tcu::Vec4 TextureCubeArray::sample (float s, float t, float r, float q, float lod) const
5279 {
5280 	return m_view.sample(getSampler(), s, t, r, q, lod);
5281 }
5282 
5283 void TextureCubeArray::sample4 (tcu::Vec4 output[4], const tcu::Vec4 packetTexcoords[4], float lodBias) const
5284 {
5285 	const float		cubeSide		= (float)m_view.getSize();
5286 	const tcu::Vec3	cubeCoords[4]	=
5287 	{
5288 		packetTexcoords[0].toWidth<3>(),
5289 		packetTexcoords[1].toWidth<3>(),
5290 		packetTexcoords[2].toWidth<3>(),
5291 		packetTexcoords[3].toWidth<3>()
5292 	};
5293 
5294 	for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
5295 	{
5296 		const tcu::CubeFace face			= tcu::selectCubeFace(cubeCoords[fragNdx]);
5297 		const tcu::Vec2		faceCoords[4]	=
5298 		{
5299 			tcu::projectToFace(face, cubeCoords[0]),
5300 			tcu::projectToFace(face, cubeCoords[1]),
5301 			tcu::projectToFace(face, cubeCoords[2]),
5302 			tcu::projectToFace(face, cubeCoords[3]),
5303 		};
5304 
5305 		const tcu::Vec2 dFdx0 = faceCoords[1] - faceCoords[0];
5306 		const tcu::Vec2 dFdx1 = faceCoords[3] - faceCoords[2];
5307 		const tcu::Vec2 dFdy0 = faceCoords[2] - faceCoords[0];
5308 		const tcu::Vec2 dFdy1 = faceCoords[3] - faceCoords[1];
5309 
5310 		const tcu::Vec2& dFdx = (fragNdx & 2) ? dFdx1 : dFdx0;
5311 		const tcu::Vec2& dFdy = (fragNdx & 1) ? dFdy1 : dFdy0;
5312 
5313 		const float mu = de::max(de::abs(dFdx.x()), de::abs(dFdy.x()));
5314 		const float mv = de::max(de::abs(dFdx.y()), de::abs(dFdy.y()));
5315 		const float p = de::max(mu * cubeSide, mv * cubeSide);
5316 
5317 		const float	lod = deFloatLog2(p) + lodBias;
5318 
5319 		output[fragNdx] = sample(packetTexcoords[fragNdx].x(), packetTexcoords[fragNdx].y(), packetTexcoords[fragNdx].z(), packetTexcoords[fragNdx].w(), lod);
5320 	}
5321 }
5322 
5323 Texture3D::Texture3D (deUint32 name)
5324 	: Texture	(name, TYPE_3D)
5325 	, m_view	(0, DE_NULL)
5326 {
5327 }
5328 
5329 Texture3D::~Texture3D (void)
5330 {
5331 }
5332 
5333 void Texture3D::allocLevel (int level, const tcu::TextureFormat& format, int width, int height, int depth)
5334 {
5335 	m_levels.allocLevel(level, format, width, height, depth);
5336 }
5337 
5338 bool Texture3D::isComplete (void) const
5339 {
5340 	const int	baseLevel	= getBaseLevel();
5341 
5342 	if (hasLevel(baseLevel))
5343 	{
5344 		const tcu::ConstPixelBufferAccess&	level0		= getLevel(baseLevel);
5345 		const bool							mipmap		= isMipmapFilter(getSampler().minFilter);
5346 
5347 		if (mipmap)
5348 		{
5349 			const TextureFormat&	format		= level0.getFormat();
5350 			const int				w			= level0.getWidth();
5351 			const int				h			= level0.getHeight();
5352 			const int				d			= level0.getDepth();
5353 			const int				numLevels	= de::min(getMaxLevel()-baseLevel+1, getNumMipLevels3D(w, h, d));
5354 
5355 			for (int levelNdx = 1; levelNdx < numLevels; levelNdx++)
5356 			{
5357 				if (hasLevel(baseLevel+levelNdx))
5358 				{
5359 					const tcu::ConstPixelBufferAccess&	level		= getLevel(baseLevel+levelNdx);
5360 					const int							expectedW	= getMipLevelSize(w, levelNdx);
5361 					const int							expectedH	= getMipLevelSize(h, levelNdx);
5362 					const int							expectedD	= getMipLevelSize(d, levelNdx);
5363 
5364 					if (level.getWidth()	!= expectedW	||
5365 						level.getHeight()	!= expectedH	||
5366 						level.getDepth()	!= expectedD	||
5367 						level.getFormat()	!= format)
5368 						return false;
5369 				}
5370 				else
5371 					return false;
5372 			}
5373 		}
5374 
5375 		return true;
5376 	}
5377 	else
5378 		return false;
5379 }
5380 
5381 tcu::Vec4 Texture3D::sample (float s, float t, float r, float lod) const
5382 {
5383 	return m_view.sample(getSampler(), s, t, r, lod);
5384 }
5385 
5386 void Texture3D::sample4 (tcu::Vec4 output[4], const tcu::Vec3 packetTexcoords[4], float lodBias) const
5387 {
5388 	const float texWidth  = (float)m_view.getWidth();
5389 	const float texHeight = (float)m_view.getHeight();
5390 	const float texDepth  = (float)m_view.getDepth();
5391 
5392 	const tcu::Vec3 dFdx0 = packetTexcoords[1] - packetTexcoords[0];
5393 	const tcu::Vec3 dFdx1 = packetTexcoords[3] - packetTexcoords[2];
5394 	const tcu::Vec3 dFdy0 = packetTexcoords[2] - packetTexcoords[0];
5395 	const tcu::Vec3 dFdy1 = packetTexcoords[3] - packetTexcoords[1];
5396 
5397 	for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
5398 	{
5399 		const tcu::Vec3& dFdx = (fragNdx & 2) ? dFdx1 : dFdx0;
5400 		const tcu::Vec3& dFdy = (fragNdx & 1) ? dFdy1 : dFdy0;
5401 
5402 		const float mu = de::max(de::abs(dFdx.x()), de::abs(dFdy.x()));
5403 		const float mv = de::max(de::abs(dFdx.y()), de::abs(dFdy.y()));
5404 		const float mw = de::max(de::abs(dFdx.z()), de::abs(dFdy.z()));
5405 		const float p = de::max(de::max(mu * texWidth, mv * texHeight), mw * texDepth);
5406 
5407 		const float	lod = deFloatLog2(p) + lodBias;
5408 
5409 		output[fragNdx] = sample(packetTexcoords[fragNdx].x(), packetTexcoords[fragNdx].y(), packetTexcoords[fragNdx].z(), lod);
5410 	}
5411 }
5412 
5413 void Texture3D::updateView (tcu::Sampler::DepthStencilMode mode)
5414 {
5415 	const int baseLevel	= getBaseLevel();
5416 
5417 	if (hasLevel(baseLevel) && !isEmpty(getLevel(baseLevel)))
5418 	{
5419 		const int	width		= getLevel(baseLevel).getWidth();
5420 		const int	height		= getLevel(baseLevel).getHeight();
5421 		const int	depth		= getLevel(baseLevel).getDepth();
5422 		const bool	isMipmap	= isMipmapFilter(getSampler().minFilter);
5423 		const int	numLevels	= isMipmap ? de::min(getMaxLevel()-baseLevel+1, getNumMipLevels3D(width, height, depth)) : 1;
5424 
5425 		m_levels.updateSamplerMode(mode);
5426 		m_view = tcu::Texture3DView(numLevels, m_levels.getEffectiveLevels() + baseLevel);
5427 	}
5428 	else
5429 		m_view = tcu::Texture3DView(0, DE_NULL);
5430 }
5431 
5432 Renderbuffer::Renderbuffer (deUint32 name)
5433 	: NamedObject		(name)
5434 {
5435 }
5436 
5437 Renderbuffer::~Renderbuffer (void)
5438 {
5439 }
5440 
5441 void Renderbuffer::setStorage (const TextureFormat& format, int width, int height)
5442 {
5443 	m_data.setStorage(format, width, height);
5444 }
5445 
5446 Framebuffer::Framebuffer (deUint32 name)
5447 	: NamedObject(name)
5448 {
5449 }
5450 
5451 Framebuffer::~Framebuffer (void)
5452 {
5453 }
5454 
5455 VertexArray::VertexArray (deUint32 name, int maxVertexAttribs)
5456 	: NamedObject					(name)
5457 	, m_elementArrayBufferBinding	(DE_NULL)
5458 	, m_arrays						(maxVertexAttribs)
5459 {
5460 	for (int i = 0; i < maxVertexAttribs; ++i)
5461 	{
5462 		m_arrays[i].enabled			= false;
5463 		m_arrays[i].size			= 4;
5464 		m_arrays[i].stride			= 0;
5465 		m_arrays[i].type			= GL_FLOAT;
5466 		m_arrays[i].normalized		= false;
5467 		m_arrays[i].integer			= false;
5468 		m_arrays[i].divisor			= 0;
5469 		m_arrays[i].bufferDeleted	= false;
5470 		m_arrays[i].bufferBinding	= DE_NULL;
5471 		m_arrays[i].pointer			= DE_NULL;
5472 	}
5473 }
5474 
5475 ShaderProgramObjectContainer::ShaderProgramObjectContainer (deUint32 name, ShaderProgram* program)
5476 	: NamedObject	(name)
5477 	, m_program		(program)
5478 	, m_deleteFlag	(false)
5479 {
5480 }
5481 
5482 ShaderProgramObjectContainer::~ShaderProgramObjectContainer (void)
5483 {
5484 }
5485 
5486 } // rc
5487 } // sglr
5488