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