1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program EGL Module
3 * ---------------------------------------
5 * Copyright 2014 The Android Open Source Project
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 * \brief Common utilities for EGL images.
22 *//*--------------------------------------------------------------------*/
25 #include "teglImageUtil.hpp"
27 #include "tcuTexture.hpp"
28 #include "tcuTextureUtil.hpp"
30 #include "egluGLUtil.hpp"
31 #include "egluNativeWindow.hpp"
32 #include "egluNativePixmap.hpp"
34 #include "eglwLibrary.hpp"
35 #include "eglwEnums.hpp"
37 #include "glwEnums.hpp"
39 #include "gluObjectWrapper.hpp"
40 #include "gluTextureUtil.hpp"
55 using tcu::TextureFormat;
59 using glu::Framebuffer;
62 using eglu::AttribMap;
63 using eglu::UniqueSurface;
64 using eglu::NativeDisplay;
65 using eglu::NativeWindow;
66 using eglu::NativePixmap;
67 using eglu::NativeDisplayFactory;
68 using eglu::NativeWindowFactory;
69 using eglu::NativePixmapFactory;
70 using eglu::WindowParams;
82 struct NativeSurface : public ManagedSurface
85 explicit NativeSurface (MovePtr<UniqueSurface> surface,
87 : ManagedSurface (surface)
88 , m_native (native) {}
91 UniquePtr<T> m_native;
94 typedef NativeSurface<NativeWindow> NativeWindowSurface;
95 typedef NativeSurface<NativePixmap> NativePixmapSurface;
97 MovePtr<ManagedSurface> createSurface (EglTestContext& eglTestCtx, EGLDisplay dpy, EGLConfig config, int width, int height)
99 const Library& egl = eglTestCtx.getLibrary();
100 EGLint surfaceTypeBits = eglu::getConfigAttribInt(egl, dpy, config, EGL_SURFACE_TYPE);
101 const NativeDisplayFactory& displayFactory = eglTestCtx.getNativeDisplayFactory();
102 NativeDisplay& nativeDisplay = eglTestCtx.getNativeDisplay();
104 if (surfaceTypeBits & EGL_PBUFFER_BIT)
106 static const EGLint attribs[] = { EGL_WIDTH, width, EGL_HEIGHT, height, EGL_NONE };
107 const EGLSurface surface = egl.createPbufferSurface(dpy, config, attribs);
109 EGLU_CHECK_MSG(egl, "eglCreatePbufferSurface()");
111 return de::newMovePtr<ManagedSurface>(MovePtr<UniqueSurface>(new UniqueSurface(egl, dpy, surface)));
113 else if (surfaceTypeBits & EGL_WINDOW_BIT)
115 const NativeWindowFactory& windowFactory = selectNativeWindowFactory(displayFactory, eglTestCtx.getTestContext().getCommandLine());
117 MovePtr<NativeWindow> window (windowFactory.createWindow(&nativeDisplay, dpy, config, DE_NULL, WindowParams(width, height, WindowParams::VISIBILITY_DONT_CARE)));
118 const EGLSurface surface = eglu::createWindowSurface(nativeDisplay, *window, dpy, config, DE_NULL);
120 return MovePtr<ManagedSurface>(new NativeWindowSurface(MovePtr<UniqueSurface>(new UniqueSurface(egl, dpy, surface)), window));
122 else if (surfaceTypeBits & EGL_PIXMAP_BIT)
124 const NativePixmapFactory& pixmapFactory = selectNativePixmapFactory(displayFactory, eglTestCtx.getTestContext().getCommandLine());
126 MovePtr<NativePixmap> pixmap (pixmapFactory.createPixmap(&nativeDisplay, dpy, config, DE_NULL, width, height));
127 const EGLSurface surface = eglu::createPixmapSurface(eglTestCtx.getNativeDisplay(), *pixmap, dpy, config, DE_NULL);
129 return MovePtr<ManagedSurface>(new NativePixmapSurface(MovePtr<UniqueSurface>(new UniqueSurface(egl, dpy, surface)), pixmap));
132 TCU_FAIL("No valid surface types supported in config");
135 class GLClientBuffer : public ClientBuffer
137 EGLClientBuffer get (void) const { return reinterpret_cast<EGLClientBuffer>(static_cast<deUintptr>(getName())); }
140 virtual GLuint getName (void) const = 0;
143 class TextureClientBuffer : public GLClientBuffer
146 TextureClientBuffer (const glw::Functions& gl) : m_texture (gl) {}
147 GLuint getName (void) const { return *m_texture; }
150 glu::Texture m_texture;
153 class GLImageSource : public ImageSource
156 EGLImageKHR createImage (const Library& egl, EGLDisplay dpy, EGLContext ctx, EGLClientBuffer clientBuffer) const;
159 virtual AttribMap getCreateAttribs (void) const = 0;
160 virtual EGLenum getSource (void) const = 0;
163 EGLImageKHR GLImageSource::createImage (const Library& egl, EGLDisplay dpy, EGLContext ctx, EGLClientBuffer clientBuffer) const
165 AttribMap attribMap = getCreateAttribs();
167 attribMap[EGL_IMAGE_PRESERVED_KHR] = EGL_TRUE;
170 const vector<EGLint> attribs = eglu::attribMapToList(attribMap);
171 const EGLImageKHR image = egl.createImageKHR(dpy, ctx, getSource(),
172 clientBuffer, &attribs.front());
173 EGLU_CHECK_MSG(egl, "eglCreateImageKHR()");
178 class TextureImageSource : public GLImageSource
181 TextureImageSource (GLenum internalFormat, GLenum format, GLenum type, bool useTexLevel0) : m_internalFormat(internalFormat), m_format(format), m_type(type), m_useTexLevel0(useTexLevel0) {}
182 MovePtr<ClientBuffer> createBuffer (const eglw::Library& egl, const glw::Functions& gl, Texture2D* reference) const;
183 GLenum getEffectiveFormat (void) const;
184 GLenum getInternalFormat (void) const { return m_internalFormat; }
187 AttribMap getCreateAttribs (void) const;
188 virtual void initTexture (const glw::Functions& gl) const = 0;
189 virtual GLenum getGLTarget (void) const = 0;
191 const GLenum m_internalFormat;
192 const GLenum m_format;
194 const bool m_useTexLevel0;
197 bool isSizedFormat (GLenum format)
201 glu::mapGLInternalFormat(format);
204 catch (const tcu::InternalError&)
210 GLenum getEffectiveFormat (GLenum format, GLenum type)
212 return glu::getInternalFormat(glu::mapGLTransferFormat(format, type));
215 GLenum TextureImageSource::getEffectiveFormat (void) const
217 if (isSizedFormat(m_internalFormat))
218 return m_internalFormat;
220 return deqp::egl::Image::getEffectiveFormat(m_format, m_type);
223 AttribMap TextureImageSource::getCreateAttribs (void) const
227 ret[EGL_GL_TEXTURE_LEVEL_KHR] = 0;
232 MovePtr<ClientBuffer> TextureImageSource::createBuffer (const eglw::Library& egl, const glw::Functions& gl, Texture2D* ref) const
236 MovePtr<TextureClientBuffer> clientBuffer (new TextureClientBuffer(gl));
237 const GLuint texture = clientBuffer->getName();
238 const GLenum target = getGLTarget();
240 GLU_CHECK_GLW_CALL(gl, bindTexture(target, texture));
245 // Set minification filter to linear. This makes the texture complete.
246 GLU_CHECK_GLW_CALL(gl, texParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
251 GLenum imgTarget = eglu::getImageGLTarget(getSource());
253 *ref = Texture2D(glu::mapGLTransferFormat(m_format, m_type), IMAGE_WIDTH, IMAGE_HEIGHT);
255 tcu::fillWithComponentGradients(ref->getLevel(0),
256 tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f),
257 tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f));
259 GLU_CHECK_GLW_CALL(gl, texParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
260 GLU_CHECK_GLW_CALL(gl, texParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
261 GLU_CHECK_GLW_CALL(gl, texParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
262 GLU_CHECK_GLW_CALL(gl, texParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
264 GLU_CHECK_GLW_CALL(gl, texImage2D(imgTarget, 0, m_internalFormat, IMAGE_WIDTH, IMAGE_HEIGHT,
265 0, m_format, m_type, ref->getLevel(0).getDataPtr()));
267 GLU_CHECK_GLW_CALL(gl, bindTexture(target, 0));
268 return MovePtr<ClientBuffer>(clientBuffer);
271 class Texture2DImageSource : public TextureImageSource
274 Texture2DImageSource (GLenum internalFormat, GLenum format, GLenum type, bool useTexLevel0) : TextureImageSource(internalFormat, format, type, useTexLevel0) {}
275 EGLenum getSource (void) const { return EGL_GL_TEXTURE_2D_KHR; }
276 string getRequiredExtension (void) const { return "EGL_KHR_gl_texture_2D_image"; }
277 GLenum getGLTarget (void) const { return GL_TEXTURE_2D; }
280 void initTexture (const glw::Functions& gl) const;
283 void Texture2DImageSource::initTexture (const glw::Functions& gl) const
285 // Specify mipmap level 0
286 GLU_CHECK_CALL_ERROR(gl.texImage2D(GL_TEXTURE_2D, 0, m_internalFormat, IMAGE_WIDTH, IMAGE_HEIGHT, 0, m_format, m_type, DE_NULL),
290 class TextureCubeMapImageSource : public TextureImageSource
293 TextureCubeMapImageSource (EGLenum source, GLenum internalFormat, GLenum format, GLenum type, bool useTexLevel0) : TextureImageSource(internalFormat, format, type, useTexLevel0), m_source(source) {}
294 EGLenum getSource (void) const { return m_source; }
295 string getRequiredExtension (void) const { return "EGL_KHR_gl_texture_cubemap_image"; }
296 GLenum getGLTarget (void) const { return GL_TEXTURE_CUBE_MAP; }
299 void initTexture (const glw::Functions& gl) const;
304 void TextureCubeMapImageSource::initTexture (const glw::Functions& gl) const
306 // Specify mipmap level 0 for all faces
307 static const GLenum faces[] =
309 GL_TEXTURE_CUBE_MAP_POSITIVE_X,
310 GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
311 GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
312 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
313 GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
314 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
317 for (int faceNdx = 0; faceNdx < DE_LENGTH_OF_ARRAY(faces); faceNdx++)
318 GLU_CHECK_GLW_CALL(gl, texImage2D(faces[faceNdx], 0, m_internalFormat, IMAGE_WIDTH, IMAGE_HEIGHT, 0, m_format, m_type, DE_NULL));
321 class RenderbufferClientBuffer : public GLClientBuffer
324 RenderbufferClientBuffer (const glw::Functions& gl) : m_rbo (gl) {}
325 GLuint getName (void) const { return *m_rbo; }
328 glu::Renderbuffer m_rbo;
331 class RenderbufferImageSource : public GLImageSource
334 RenderbufferImageSource (GLenum format) : m_format(format) {}
336 string getRequiredExtension (void) const { return "EGL_KHR_gl_renderbuffer_image"; }
337 MovePtr<ClientBuffer> createBuffer (const eglw::Library& egl, const glw::Functions& gl, Texture2D* reference) const;
338 GLenum getEffectiveFormat (void) const { return m_format; }
341 EGLenum getSource (void) const { return EGL_GL_RENDERBUFFER_KHR; }
342 AttribMap getCreateAttribs (void) const { return AttribMap(); }
347 void initializeStencilRbo(const glw::Functions& gl, GLuint rbo, Texture2D& ref)
349 static const deUint32 stencilValues[] =
363 const deUint32 numStencilBits = tcu::getTextureFormatBitDepth(tcu::getEffectiveDepthStencilTextureFormat(ref.getLevel(0).getFormat(), tcu::Sampler::MODE_STENCIL)).x();
364 const deUint32 stencilMask = deBitMask32(0, numStencilBits);
366 GLU_CHECK_GLW_CALL(gl, framebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
367 GL_RENDERBUFFER, rbo));
368 GLU_CHECK_GLW_CALL(gl, clearStencil(0));
369 GLU_CHECK_GLW_CALL(gl, clear(GL_STENCIL_BUFFER_BIT));
370 tcu::clearStencil(ref.getLevel(0), 0);
373 GLU_CHECK_GLW_CALL(gl, enable(GL_SCISSOR_TEST));
374 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(stencilValues); ++ndx)
376 const deUint32 stencil = stencilValues[ndx] & stencilMask;
377 const tcu::IVec2 size = tcu::IVec2((int)((float)(DE_LENGTH_OF_ARRAY(stencilValues) - ndx) * ((float)ref.getWidth() / float(DE_LENGTH_OF_ARRAY(stencilValues)))),
378 (int)((float)(DE_LENGTH_OF_ARRAY(stencilValues) - ndx) * ((float)ref.getHeight() / float(DE_LENGTH_OF_ARRAY(stencilValues) + 4)))); // not symmetric
380 if (size.x() == 0 || size.y() == 0)
383 GLU_CHECK_GLW_CALL(gl, scissor(0, 0, size.x(), size.y()));
384 GLU_CHECK_GLW_CALL(gl, clearStencil(stencil));
385 GLU_CHECK_GLW_CALL(gl, clear(GL_STENCIL_BUFFER_BIT));
387 tcu::clearStencil(tcu::getSubregion(ref.getLevel(0), 0, 0, size.x(), size.y()), stencil);
390 GLU_CHECK_GLW_CALL(gl, disable(GL_SCISSOR_TEST));
391 GLU_CHECK_GLW_CALL(gl, framebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
392 GL_RENDERBUFFER, 0));
395 void initializeDepthRbo(const glw::Functions& gl, GLuint rbo, Texture2D& ref)
397 const int NUM_STEPS = 13;
399 GLU_CHECK_GLW_CALL(gl, framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
400 GL_RENDERBUFFER, rbo));
402 GLU_CHECK_GLW_CALL(gl, clearDepthf(0.0f));
403 GLU_CHECK_GLW_CALL(gl, clear(GL_DEPTH_BUFFER_BIT));
404 tcu::clearDepth(ref.getLevel(0), 0.0f);
407 GLU_CHECK_GLW_CALL(gl, enable(GL_SCISSOR_TEST));
408 for (int ndx = 0; ndx < NUM_STEPS; ++ndx)
410 const float depth = (float)ndx / float(NUM_STEPS);
411 const tcu::IVec2 size = tcu::IVec2((int)((float)(NUM_STEPS - ndx) * ((float)ref.getWidth() / float(NUM_STEPS))),
412 (int)((float)(NUM_STEPS - ndx) * ((float)ref.getHeight() / float(NUM_STEPS + 4)))); // not symmetric
414 if (size.x() == 0 || size.y() == 0)
417 GLU_CHECK_GLW_CALL(gl, scissor(0, 0, size.x(), size.y()));
418 GLU_CHECK_GLW_CALL(gl, clearDepthf(depth));
419 GLU_CHECK_GLW_CALL(gl, clear(GL_DEPTH_BUFFER_BIT));
421 tcu::clearDepth(tcu::getSubregion(ref.getLevel(0), 0, 0, size.x(), size.y()), depth);
424 GLU_CHECK_GLW_CALL(gl, disable(GL_SCISSOR_TEST));
425 GLU_CHECK_GLW_CALL(gl, framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
426 GL_RENDERBUFFER, 0));
430 void initializeColorRbo(const glw::Functions& gl, GLuint rbo, Texture2D& ref)
432 static const tcu::Vec4 colorValues[] =
434 tcu::Vec4(0.9f, 0.5f, 0.65f, 1.0f),
435 tcu::Vec4(0.5f, 0.7f, 0.65f, 1.0f),
436 tcu::Vec4(0.2f, 0.5f, 0.65f, 1.0f),
437 tcu::Vec4(0.3f, 0.1f, 0.5f, 1.0f),
438 tcu::Vec4(0.8f, 0.2f, 0.3f, 1.0f),
439 tcu::Vec4(0.9f, 0.4f, 0.8f, 1.0f),
442 GLU_CHECK_GLW_CALL(gl, framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
443 GL_RENDERBUFFER, rbo));
444 GLU_CHECK_GLW_CALL(gl, clearColor(1.0f, 1.0f, 0.0f, 1.0f));
445 GLU_CHECK_GLW_CALL(gl, clear(GL_COLOR_BUFFER_BIT));
446 tcu::clear(ref.getLevel(0), Vec4(1.0f, 1.0f, 0.0f, 1.0f));
449 GLU_CHECK_GLW_CALL(gl, enable(GL_SCISSOR_TEST));
450 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(colorValues); ++ndx)
452 const tcu::IVec2 size = tcu::IVec2((int)((float)(DE_LENGTH_OF_ARRAY(colorValues) - ndx) * ((float)ref.getWidth() / float(DE_LENGTH_OF_ARRAY(colorValues)))),
453 (int)((float)(DE_LENGTH_OF_ARRAY(colorValues) - ndx) * ((float)ref.getHeight() / float(DE_LENGTH_OF_ARRAY(colorValues) + 4)))); // not symmetric
455 if (size.x() == 0 || size.y() == 0)
458 GLU_CHECK_GLW_CALL(gl, scissor(0, 0, size.x(), size.y()));
459 GLU_CHECK_GLW_CALL(gl, clearColor(colorValues[ndx].x(), colorValues[ndx].y(), colorValues[ndx].z(), colorValues[ndx].w()));
460 GLU_CHECK_GLW_CALL(gl, clear(GL_COLOR_BUFFER_BIT));
462 tcu::clear(tcu::getSubregion(ref.getLevel(0), 0, 0, size.x(), size.y()), colorValues[ndx]);
465 GLU_CHECK_GLW_CALL(gl, disable(GL_SCISSOR_TEST));
466 GLU_CHECK_GLW_CALL(gl, framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
467 GL_RENDERBUFFER, 0));
470 MovePtr<ClientBuffer> RenderbufferImageSource::createBuffer (const eglw::Library& egl, const glw::Functions& gl, Texture2D* ref) const
474 MovePtr<RenderbufferClientBuffer> buffer (new RenderbufferClientBuffer(gl));
475 const GLuint rbo = buffer->getName();
477 GLU_CHECK_CALL_ERROR(gl.bindRenderbuffer(GL_RENDERBUFFER, rbo), gl.getError());
480 GLU_CHECK_CALL_ERROR(gl.renderbufferStorage(GL_RENDERBUFFER, m_format, 64, 64), gl.getError());
484 Framebuffer fbo (gl);
485 const TextureFormat texFormat = glu::mapGLInternalFormat(m_format);
487 *ref = tcu::Texture2D(texFormat, 64, 64);
490 gl.bindFramebuffer(GL_FRAMEBUFFER, *fbo);
493 case GL_STENCIL_INDEX8:
494 initializeStencilRbo(gl, rbo, *ref);
496 case GL_DEPTH_COMPONENT16:
497 initializeDepthRbo(gl, rbo, *ref);
500 initializeColorRbo(gl, rbo, *ref);
503 initializeColorRbo(gl, rbo, *ref);
506 initializeColorRbo(gl, rbo, *ref);
509 DE_FATAL("Impossible");
512 gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
515 return MovePtr<ClientBuffer>(buffer);
518 class UnsupportedImageSource : public ImageSource
521 UnsupportedImageSource (const string& message, GLenum format, bool isYUV) : m_message(message), m_format(format), m_isY8Cb8Cr8_420(isYUV) {}
522 string getRequiredExtension (void) const { fail(); return ""; }
523 MovePtr<ClientBuffer> createBuffer (const eglw::Library& egl, const glw::Functions&, tcu::Texture2D*) const { DE_UNREF(egl); fail(); return de::MovePtr<ClientBuffer>(); }
524 EGLImageKHR createImage (const Library& egl, EGLDisplay dpy, EGLContext ctx, EGLClientBuffer clientBuffer) const;
525 GLenum getEffectiveFormat (void) const { return m_format; }
526 bool isYUVFormatImage (void) const {return m_isY8Cb8Cr8_420;};
528 const string m_message;
530 bool m_isY8Cb8Cr8_420;
531 void fail (void) const { TCU_THROW(NotSupportedError, m_message.c_str()); }
534 EGLImageKHR UnsupportedImageSource::createImage (const Library&, EGLDisplay, EGLContext, EGLClientBuffer) const
537 return EGL_NO_IMAGE_KHR;
540 MovePtr<ImageSource> createTextureImageSource (EGLenum source, GLenum internalFormat, GLenum format, GLenum type, bool useTexLevel0)
542 if (source == EGL_GL_TEXTURE_2D_KHR)
543 return MovePtr<ImageSource>(new Texture2DImageSource(internalFormat, format, type, useTexLevel0));
545 return MovePtr<ImageSource>(new TextureCubeMapImageSource(source, internalFormat, format, type, useTexLevel0));
548 MovePtr<ImageSource> createRenderbufferImageSource (GLenum format)
550 return MovePtr<ImageSource>(new RenderbufferImageSource(format));
553 MovePtr<ImageSource> createUnsupportedImageSource (const string& message, GLenum format, bool isYUV)
555 return MovePtr<ImageSource>(new UnsupportedImageSource(message, format, isYUV));