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