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