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