Merge "Merge "DEPTH_STENCIL_OES as tex format requires OES_depth_texture" into nougat...
[platform/upstream/VK-GL-CTS.git] / framework / opengl / simplereference / sglrReferenceContext.cpp
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
39 namespace sglr
40 {
41
42 using std::vector;
43 using std::map;
44
45 using tcu::Vec2;
46 using tcu::Vec3;
47 using tcu::Vec4;
48 using tcu::IVec2;
49 using tcu::IVec4;
50 using tcu::RGBA;
51
52 // Reference context implementation
53 using namespace rc;
54
55 using tcu::TextureFormat;
56 using tcu::PixelBufferAccess;
57 using tcu::ConstPixelBufferAccess;
58
59 // Utilities for ReferenceContext
60 #define RC_RET_VOID
61
62 #define RC_ERROR_RET(ERR, RET)                  \
63 do {                                                                    \
64         setError(ERR);                                          \
65         return RET;                                                     \
66 } while (deGetFalse())
67
68 #define RC_IF_ERROR(COND, ERR, RET)             \
69 do {                                                                    \
70         if (COND)                                                       \
71                 RC_ERROR_RET(ERR, RET);                 \
72 } while (deGetFalse())
73
74 static inline tcu::PixelBufferAccess nullAccess (void)
75 {
76         return tcu::PixelBufferAccess(TextureFormat(TextureFormat::R, TextureFormat::UNSIGNED_INT8), 0, 0, 0, DE_NULL);
77 }
78
79 static inline bool isEmpty (const tcu::ConstPixelBufferAccess& access)
80 {
81         return access.getWidth() == 0 || access.getHeight() == 0 || access.getDepth() == 0;
82 }
83
84 static inline bool isEmpty (const rr::MultisampleConstPixelBufferAccess& access)
85 {
86         return access.raw().getWidth() == 0 || access.raw().getHeight() == 0 || access.raw().getDepth() == 0;
87 }
88
89 static inline bool isEmpty (const IVec4& rect)
90 {
91         return rect.z() == 0 || rect.w() == 0;
92 }
93
94 inline int getNumMipLevels1D (int size)
95 {
96         return deLog2Floor32(size)+1;
97 }
98
99 inline int getNumMipLevels2D (int width, int height)
100 {
101         return deLog2Floor32(de::max(width, height))+1;
102 }
103
104 inline int getNumMipLevels3D (int width, int height, int depth)
105 {
106         return deLog2Floor32(de::max(width, de::max(height, depth)))+1;
107 }
108
109 inline int getMipLevelSize (int baseLevelSize, int levelNdx)
110 {
111         return de::max(baseLevelSize >> levelNdx, 1);
112 }
113
114 inline bool isMipmapFilter (const tcu::Sampler::FilterMode mode)
115 {
116         return mode != tcu::Sampler::NEAREST && mode != tcu::Sampler::LINEAR;
117 }
118
119 static 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
133 static 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
144 static 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
158 tcu::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
182 tcu::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
195 tcu::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
208 tcu::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
221 static 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
233 static inline tcu::IVec4 getBufferRect (const rr::MultisampleConstPixelBufferAccess& access)
234 {
235         return tcu::IVec4(0, 0, access.raw().getHeight(), access.raw().getDepth());
236 }
237
238 ReferenceContextLimits::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
281 void ReferenceContextLimits::addExtension (const char* extension)
282 {
283         extensionList.push_back(extension);
284
285         if (!extensionStr.empty())
286                 extensionStr += " ";
287         extensionStr += extension;
288 }
289
290 ReferenceContextBuffers::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
301 ReferenceContext::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
312 ReferenceContext::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
446 ReferenceContext::~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
494 void 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
502 void 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
517 void 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
532 void 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
547 void 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
562 void 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
577 void 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
592 void 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
674 void ReferenceContext::genTextures (int numTextures, deUint32* textures)
675 {
676         while (numTextures--)
677                 *textures++ = m_textures.allocateName();
678 }
679
680 void 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
692 void 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
731 void 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
781 void ReferenceContext::genFramebuffers (int numFramebuffers, deUint32* framebuffers)
782 {
783         while (numFramebuffers--)
784                 *framebuffers++ = m_framebuffers.allocateName();
785 }
786
787 void 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
797 void 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
809 void 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
836 void ReferenceContext::genRenderbuffers (int numRenderbuffers, deUint32* renderbuffers)
837 {
838         while (numRenderbuffers--)
839                 *renderbuffers++ = m_renderbuffers.allocateName();
840 }
841
842 void 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
873 void 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
885 void 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
929 tcu::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
939 tcu::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
951 static 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
966 static 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
997 void 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
1002 void 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
1007 static 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
1021 void 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
1277 void 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
1282 void 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
1287 void ReferenceContext::texSubImage3D (deUint32 target, int level, int xoffset, int yoffset, int zoffset, int width, int height, int depth, deUint32 format, deUint32 type, const void* data)
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
1424 void 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
1472 void 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
1559 void 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
1590 void 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
1651 void 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
1657 void 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
1711 void 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
1792 static 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
1803 static 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
1817 void 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
1889 static 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
1900 static 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
1915 void 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
1942 void 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
1969 void 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
2031 void 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
2101 void 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
2151 deUint32 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
2302 void 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
2308 void 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
2323 void 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
2330 tcu::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
2379 const Texture2D& ReferenceContext::getTexture2D (int unitNdx) const
2380 {
2381         const TextureUnit& unit = m_textureUnits[unitNdx];
2382         return unit.tex2DBinding ? *unit.tex2DBinding : unit.default2DTex;
2383 }
2384
2385 const TextureCube& ReferenceContext::getTextureCube (int unitNdx) const
2386 {
2387         const TextureUnit& unit = m_textureUnits[unitNdx];
2388         return unit.texCubeBinding ? *unit.texCubeBinding : unit.defaultCubeTex;
2389 }
2390
2391 static 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
2411 void 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
2444 DataBuffer* 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
2465 void 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
2484 void 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
2492 void 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
2511 void 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
2561 void 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
2577 void 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
2590 void 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
2598 void ReferenceContext::clearDepthf (float depth)
2599 {
2600         m_clearDepth = de::clamp(depth, 0.0f, 1.0f);
2601 }
2602
2603 void ReferenceContext::clearStencil (int stencil)
2604 {
2605         m_clearStencil = stencil;
2606 }
2607
2608 void 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
2614 void 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
2670 void 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
2725 static 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
2744 static 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
2763 void ReferenceContext::stencilFunc (deUint32 func, int ref, deUint32 mask)
2764 {
2765         stencilFuncSeparate(GL_FRONT_AND_BACK, func, ref, mask);
2766 }
2767
2768 void 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
2788 void ReferenceContext::stencilOp (deUint32 sfail, deUint32 dpfail, deUint32 dppass)
2789 {
2790         stencilOpSeparate(GL_FRONT_AND_BACK, sfail, dpfail, dppass);
2791 }
2792
2793 void 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
2816 void ReferenceContext::depthFunc (deUint32 func)
2817 {
2818         RC_IF_ERROR(!isValidCompareFunc(func), GL_INVALID_ENUM, RC_RET_VOID);
2819         m_depthFunc = func;
2820 }
2821
2822 void 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
2828 void ReferenceContext::depthRange (double n, double f)
2829 {
2830         depthRangef((float)n, (float)f);
2831 }
2832
2833 void ReferenceContext::polygonOffset (float factor, float units)
2834 {
2835         m_polygonOffsetFactor = factor;
2836         m_polygonOffsetUnits = units;
2837 }
2838
2839 void 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
2854 void ReferenceContext::primitiveRestartIndex (deUint32 index)
2855 {
2856         // only in core
2857         DE_ASSERT(glu::isContextTypeGLCore(getType()));
2858         m_primitiveRestartIndex = index;
2859 }
2860
2861 static 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
2870 static 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
2896 void 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
2904 void 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
2914 void 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
2926 void 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
2940 void 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
2948 void ReferenceContext::colorMask (deBool r, deBool g, deBool b, deBool a)
2949 {
2950         m_colorMask = tcu::BVec4(!!r, !!g, !!b, !!a);
2951 }
2952
2953 void ReferenceContext::depthMask (deBool mask)
2954 {
2955         m_depthMask = !!mask;
2956 }
2957
2958 void ReferenceContext::stencilMask (deUint32 mask)
2959 {
2960         stencilMaskSeparate(GL_FRONT_AND_BACK, mask);
2961 }
2962
2963 void 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
2974 static 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
3005 static inline deUint32 maskStencil (int numBits, deUint32 s)
3006 {
3007         return s & deBitMask32(0, numBits);
3008 }
3009
3010 static 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
3019 static 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
3024 static rr::MultisamplePixelBufferAccess getDepthMultisampleAccess (const rr::MultisamplePixelBufferAccess& combinedDSaccess)
3025 {
3026         return rr::MultisamplePixelBufferAccess::fromMultisampleAccess(tcu::getEffectiveDepthStencilAccess(combinedDSaccess.raw(), tcu::Sampler::MODE_DEPTH));
3027 }
3028
3029 static rr::MultisamplePixelBufferAccess getStencilMultisampleAccess (const rr::MultisamplePixelBufferAccess& combinedDSaccess)
3030 {
3031         return rr::MultisamplePixelBufferAccess::fromMultisampleAccess(tcu::getEffectiveDepthStencilAccess(combinedDSaccess.raw(), tcu::Sampler::MODE_STENCIL));
3032 }
3033
3034 deUint32 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
3109 void 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
3280 void 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
3336 void 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
3356 void 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
3416 void 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
3466 void 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
3516 void 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
3548 void 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
3555 void 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
3580 void 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
3588 void 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
3600 void 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
3641 void 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
3672 void 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
3680 void 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
3688 void 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
3696 void 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
3703 void 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
3710 void 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
3717 void 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
3724 void 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
3731 void 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
3738 deInt32 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
3756 void 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
3776 void 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
3817 void ReferenceContext::uniform1f (deInt32 location, const float v0)
3818 {
3819         uniform1fv(location, 1, &v0);
3820 }
3821
3822 void ReferenceContext::uniform1i (deInt32 location, deInt32 v0)
3823 {
3824         uniform1iv(location, 1, &v0);
3825 }
3826
3827 void ReferenceContext::uniform1fv (deInt32 location, deInt32 count, const float* v)
3828 {
3829         uniformv(location, glu::TYPE_FLOAT, count, v);
3830 }
3831
3832 void ReferenceContext::uniform2fv (deInt32 location, deInt32 count, const float* v)
3833 {
3834         uniformv(location, glu::TYPE_FLOAT_VEC2, count, v);
3835 }
3836
3837 void ReferenceContext::uniform3fv (deInt32 location, deInt32 count, const float* v)
3838 {
3839         uniformv(location, glu::TYPE_FLOAT_VEC3, count, v);
3840 }
3841
3842 void ReferenceContext::uniform4fv (deInt32 location, deInt32 count, const float* v)
3843 {
3844         uniformv(location, glu::TYPE_FLOAT_VEC4, count, v);
3845 }
3846
3847 void ReferenceContext::uniform2iv (deInt32 location, deInt32 count, const deInt32* v)
3848 {
3849         uniformv(location, glu::TYPE_INT_VEC2, count, v);
3850 }
3851
3852 void ReferenceContext::uniform3iv (deInt32 location, deInt32 count, const deInt32* v)
3853 {
3854         uniformv(location, glu::TYPE_INT_VEC3, count, v);
3855 }
3856
3857 void ReferenceContext::uniform4iv (deInt32 location, deInt32 count, const deInt32* v)
3858 {
3859         uniformv(location, glu::TYPE_INT_VEC4, count, v);
3860 }
3861
3862 void 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
3900 void 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
3938 deInt32 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
3952 void ReferenceContext::lineWidth (float w)
3953 {
3954         RC_IF_ERROR(w < 0.0f, GL_INVALID_VALUE, RC_RET_VOID);
3955         m_lineWidth = w;
3956 }
3957
3958 void 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
3974 void 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
3991 void ReferenceContext::drawArrays (deUint32 mode, int first, int count)
3992 {
3993         drawArraysInstanced(mode, first, count, 1);
3994 }
3995
3996 void 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
4014 void ReferenceContext::drawElements (deUint32 mode, int count, deUint32 type, const void *indices)
4015 {
4016         drawElementsInstanced(mode, count, type, indices, 1);
4017 }
4018
4019 void ReferenceContext::drawElementsBaseVertex (deUint32 mode, int count, deUint32 type, const void *indices, int baseVertex)
4020 {
4021         drawElementsInstancedBaseVertex(mode, count, type, indices, 1, baseVertex);
4022 }
4023
4024 void ReferenceContext::drawElementsInstanced (deUint32 mode, int count, deUint32 type, const void *indices, int instanceCount)
4025 {
4026         drawElementsInstancedBaseVertex(mode, count, type, indices, instanceCount, 0);
4027 }
4028
4029 void 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
4053 void 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
4060 void 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
4067 void 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
4102 void 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
4152 void 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
4163 void 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
4175 void 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
4188 bool 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
4235 static 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
4262 static 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
4277 void 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
4536 deUint32 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
4545 void 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
4571 void 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
4591 void 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
4611 deUint32 ReferenceContext::getError (void)
4612 {
4613         deUint32 err = m_lastError;
4614         m_lastError = GL_NO_ERROR;
4615         return err;
4616 }
4617
4618 void ReferenceContext::finish (void)
4619 {
4620 }
4621
4622 inline void ReferenceContext::setError (deUint32 error)
4623 {
4624         if (m_lastError == GL_NO_ERROR)
4625                 m_lastError = error;
4626 }
4627
4628 void 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
4646 const 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
4658 namespace rc
4659 {
4660
4661 TextureLevelArray::TextureLevelArray (void)
4662 {
4663 }
4664
4665 TextureLevelArray::~TextureLevelArray (void)
4666 {
4667         clear();
4668 }
4669
4670 void 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
4681 void 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
4694 void 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
4702 void 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
4708 Texture::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
4729 Texture1D::Texture1D (deUint32 name)
4730         : Texture       (name, TYPE_1D)
4731         , m_view        (0, DE_NULL)
4732 {
4733 }
4734
4735 Texture1D::~Texture1D (void)
4736 {
4737 }
4738
4739 void Texture1D::allocLevel (int level, const tcu::TextureFormat& format, int width)
4740 {
4741         m_levels.allocLevel(level, format, width, 1, 1);
4742 }
4743
4744 bool 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
4781 tcu::Vec4 Texture1D::sample (float s, float lod) const
4782 {
4783         return m_view.sample(getSampler(), s, 0.0f, lod);
4784 }
4785
4786 void 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
4809 void 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
4826 Texture2D::Texture2D (deUint32 name)
4827         : Texture       (name, TYPE_2D)
4828         , m_view        (0, DE_NULL)
4829 {
4830 }
4831
4832 Texture2D::~Texture2D (void)
4833 {
4834 }
4835
4836 void Texture2D::allocLevel (int level, const tcu::TextureFormat& format, int width, int height)
4837 {
4838         m_levels.allocLevel(level, format, width, height, 1);
4839 }
4840
4841 bool 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
4881 void 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
4900 tcu::Vec4 Texture2D::sample (float s, float t, float lod) const
4901 {
4902         return m_view.sample(getSampler(), s, t, lod);
4903 }
4904
4905 void 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
4930 TextureCube::TextureCube (deUint32 name)
4931         : Texture(name, TYPE_CUBE_MAP)
4932 {
4933 }
4934
4935 TextureCube::~TextureCube (void)
4936 {
4937 }
4938
4939 void TextureCube::clearLevels (void)
4940 {
4941         for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
4942                 m_levels[face].clear();
4943 }
4944
4945 void 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
4950 bool 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
4993 void 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
5018 tcu::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
5023 void 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
5058 Texture2DArray::Texture2DArray (deUint32 name)
5059         : Texture       (name, TYPE_2D_ARRAY)
5060         , m_view        (0, DE_NULL)
5061 {
5062 }
5063
5064 Texture2DArray::~Texture2DArray (void)
5065 {
5066 }
5067
5068 void 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
5073 bool 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
5115 void 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
5133 tcu::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
5138 void 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
5163 TextureCubeArray::TextureCubeArray (deUint32 name)
5164         : Texture       (name, TYPE_CUBE_MAP_ARRAY)
5165         , m_view        (0, DE_NULL)
5166 {
5167 }
5168
5169 TextureCubeArray::~TextureCubeArray (void)
5170 {
5171 }
5172
5173 void 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
5179 bool 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
5221 void 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
5239 tcu::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
5244 void 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
5284 Texture3D::Texture3D (deUint32 name)
5285         : Texture       (name, TYPE_3D)
5286         , m_view        (0, DE_NULL)
5287 {
5288 }
5289
5290 Texture3D::~Texture3D (void)
5291 {
5292 }
5293
5294 void 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
5299 bool 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
5342 tcu::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
5347 void 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
5374 void 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
5393 Renderbuffer::Renderbuffer (deUint32 name)
5394         : NamedObject           (name)
5395 {
5396 }
5397
5398 Renderbuffer::~Renderbuffer (void)
5399 {
5400 }
5401
5402 void Renderbuffer::setStorage (const TextureFormat& format, int width, int height)
5403 {
5404         m_data.setStorage(format, width, height);
5405 }
5406
5407 Framebuffer::Framebuffer (deUint32 name)
5408         : NamedObject(name)
5409 {
5410 }
5411
5412 Framebuffer::~Framebuffer (void)
5413 {
5414 }
5415
5416 VertexArray::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
5436 ShaderProgramObjectContainer::ShaderProgramObjectContainer (deUint32 name, ShaderProgram* program)
5437         : NamedObject   (name)
5438         , m_program             (program)
5439         , m_deleteFlag  (false)
5440 {
5441 }
5442
5443 ShaderProgramObjectContainer::~ShaderProgramObjectContainer (void)
5444 {
5445 }
5446
5447 } // rc
5448 } // sglr