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