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