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