teglImageUtil.cpp revision 7f2e8aa43396923cff333c4b4e17773589e19c17
1/*------------------------------------------------------------------------- 2 * drawElements Quality Program EGL Module 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 Common utilities for EGL images. 22 *//*--------------------------------------------------------------------*/ 23 24 25#include "teglImageUtil.hpp" 26 27#include "tcuTexture.hpp" 28#include "tcuTextureUtil.hpp" 29 30#include "egluGLUtil.hpp" 31#include "egluNativeWindow.hpp" 32#include "egluNativePixmap.hpp" 33 34#include "eglwLibrary.hpp" 35#include "eglwEnums.hpp" 36 37#include "glwEnums.hpp" 38 39#include "gluObjectWrapper.hpp" 40#include "gluTextureUtil.hpp" 41 42namespace deqp 43{ 44namespace egl 45{ 46namespace Image 47{ 48 49using std::string; 50using std::vector; 51 52using de::UniquePtr; 53using de::MovePtr; 54 55using tcu::TextureFormat; 56using tcu::Texture2D; 57using tcu::Vec4; 58 59using glu::Framebuffer; 60using glu::Texture; 61 62using eglu::AttribMap; 63using eglu::UniqueSurface; 64using eglu::NativeDisplay; 65using eglu::NativeWindow; 66using eglu::NativePixmap; 67using eglu::NativeDisplayFactory; 68using eglu::NativeWindowFactory; 69using eglu::NativePixmapFactory; 70using eglu::WindowParams; 71 72using namespace glw; 73using namespace eglw; 74 75enum { 76 IMAGE_WIDTH = 64, 77 IMAGE_HEIGHT = 64, 78}; 79 80 81template <typename T> 82struct NativeSurface : public ManagedSurface 83{ 84public: 85 explicit NativeSurface (MovePtr<UniqueSurface> surface, 86 MovePtr<T> native) 87 : ManagedSurface (surface) 88 , m_native (native) {} 89 90private: 91 UniquePtr<T> m_native; 92}; 93 94typedef NativeSurface<NativeWindow> NativeWindowSurface; 95typedef NativeSurface<NativePixmap> NativePixmapSurface; 96 97MovePtr<ManagedSurface> createSurface (EglTestContext& eglTestCtx, EGLDisplay dpy, EGLConfig config, int width, int height) 98{ 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(); 103 104 if (surfaceTypeBits & EGL_PBUFFER_BIT) 105 { 106 static const EGLint attribs[] = { EGL_WIDTH, width, EGL_HEIGHT, height, EGL_NONE }; 107 const EGLSurface surface = egl.createPbufferSurface(dpy, config, attribs); 108 109 EGLU_CHECK_MSG(egl, "eglCreatePbufferSurface()"); 110 111 return de::newMovePtr<ManagedSurface>(MovePtr<UniqueSurface>(new UniqueSurface(egl, dpy, surface))); 112 } 113 else if (surfaceTypeBits & EGL_WINDOW_BIT) 114 { 115 const NativeWindowFactory& windowFactory = selectNativeWindowFactory(displayFactory, eglTestCtx.getTestContext().getCommandLine()); 116 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); 119 120 return MovePtr<ManagedSurface>(new NativeWindowSurface(MovePtr<UniqueSurface>(new UniqueSurface(egl, dpy, surface)), window)); 121 } 122 else if (surfaceTypeBits & EGL_PIXMAP_BIT) 123 { 124 const NativePixmapFactory& pixmapFactory = selectNativePixmapFactory(displayFactory, eglTestCtx.getTestContext().getCommandLine()); 125 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); 128 129 return MovePtr<ManagedSurface>(new NativePixmapSurface(MovePtr<UniqueSurface>(new UniqueSurface(egl, dpy, surface)), pixmap)); 130 } 131 else 132 TCU_FAIL("No valid surface types supported in config"); 133} 134 135class GLClientBuffer : public ClientBuffer 136{ 137 EGLClientBuffer get (void) const { return reinterpret_cast<EGLClientBuffer>(static_cast<deUintptr>(getName())); } 138 139protected: 140 virtual GLuint getName (void) const = 0; 141}; 142 143class TextureClientBuffer : public GLClientBuffer 144{ 145public: 146 TextureClientBuffer (const glw::Functions& gl) : m_texture (gl) {} 147 GLuint getName (void) const { return *m_texture; } 148 149private: 150 glu::Texture m_texture; 151}; 152 153class GLImageSource : public ImageSource 154{ 155public: 156 EGLImageKHR createImage (const Library& egl, EGLDisplay dpy, EGLContext ctx, EGLClientBuffer clientBuffer) const; 157 158protected: 159 virtual AttribMap getCreateAttribs (void) const = 0; 160 virtual EGLenum getSource (void) const = 0; 161}; 162 163EGLImageKHR GLImageSource::createImage (const Library& egl, EGLDisplay dpy, EGLContext ctx, EGLClientBuffer clientBuffer) const 164{ 165 AttribMap attribMap = getCreateAttribs(); 166 167 attribMap[EGL_IMAGE_PRESERVED_KHR] = EGL_TRUE; 168 169 { 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()"); 174 return image; 175 } 176} 177 178class TextureImageSource : public GLImageSource 179{ 180public: 181 TextureImageSource (GLenum format, GLenum type, bool useTexLevel0) : m_format(format), m_type(type), m_useTexLevel0(useTexLevel0) {} 182 MovePtr<ClientBuffer> createBuffer (const glw::Functions& gl, Texture2D* reference) const; 183 GLenum getFormat (void) const { return m_format; } 184 185protected: 186 AttribMap getCreateAttribs (void) const; 187 virtual void initTexture (const glw::Functions& gl) const = 0; 188 virtual GLenum getGLTarget (void) const = 0; 189 190 GLenum m_format; 191 GLenum m_type; 192 bool m_useTexLevel0; 193}; 194 195AttribMap TextureImageSource::getCreateAttribs (void) const 196{ 197 AttribMap ret; 198 199 ret[EGL_GL_TEXTURE_LEVEL_KHR] = 0; 200 201 return ret; 202} 203 204MovePtr<ClientBuffer> TextureImageSource::createBuffer (const glw::Functions& gl, Texture2D* ref) const 205{ 206 MovePtr<TextureClientBuffer> clientBuffer (new TextureClientBuffer(gl)); 207 const GLuint texture = clientBuffer->getName(); 208 const GLenum target = getGLTarget(); 209 210 GLU_CHECK_GLW_CALL(gl, bindTexture(target, texture)); 211 initTexture(gl); 212 213 if (!m_useTexLevel0) 214 { 215 // Set minification filter to linear. This makes the texture complete. 216 GLU_CHECK_GLW_CALL(gl, texParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); 217 } 218 219 if (ref != DE_NULL) 220 { 221 GLenum imgTarget = eglu::getImageGLTarget(getSource()); 222 223 *ref = Texture2D(glu::mapGLTransferFormat(m_format, m_type), IMAGE_WIDTH, IMAGE_HEIGHT); 224 ref->allocLevel(0); 225 tcu::fillWithComponentGradients(ref->getLevel(0), 226 tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f), 227 tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f)); 228 229 GLU_CHECK_GLW_CALL(gl, texParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); 230 GLU_CHECK_GLW_CALL(gl, texParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); 231 GLU_CHECK_GLW_CALL(gl, texParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); 232 GLU_CHECK_GLW_CALL(gl, texParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); 233 234 GLU_CHECK_GLW_CALL(gl, texImage2D(imgTarget, 0, m_format, IMAGE_WIDTH, IMAGE_HEIGHT, 235 0, m_format, m_type, ref->getLevel(0).getDataPtr())); 236 } 237 GLU_CHECK_GLW_CALL(gl, bindTexture(target, 0)); 238 return MovePtr<ClientBuffer>(clientBuffer); 239} 240 241class Texture2DImageSource : public TextureImageSource 242{ 243public: 244 Texture2DImageSource (GLenum format, GLenum type, bool useTexLevel0) : TextureImageSource(format, type, useTexLevel0) {} 245 EGLenum getSource (void) const { return EGL_GL_TEXTURE_2D_KHR; } 246 string getRequiredExtension (void) const { return "EGL_KHR_gl_texture_2D_image"; } 247 GLenum getGLTarget (void) const { return GL_TEXTURE_2D; } 248 249protected: 250 void initTexture (const glw::Functions& gl) const; 251}; 252 253void Texture2DImageSource::initTexture (const glw::Functions& gl) const 254{ 255 // Specify mipmap level 0 256 GLU_CHECK_CALL_ERROR(gl.texImage2D(GL_TEXTURE_2D, 0, m_format, IMAGE_WIDTH, IMAGE_HEIGHT, 0, m_format, m_type, DE_NULL), 257 gl.getError()); 258} 259 260class TextureCubeMapImageSource : public TextureImageSource 261{ 262public: 263 TextureCubeMapImageSource (EGLenum source, GLenum format, GLenum type, bool useTexLevel0) : TextureImageSource(format, type, useTexLevel0), m_source(source) {} 264 EGLenum getSource (void) const { return m_source; } 265 string getRequiredExtension (void) const { return "EGL_KHR_gl_texture_cubemap_image"; } 266 GLenum getGLTarget (void) const { return GL_TEXTURE_CUBE_MAP; } 267 268protected: 269 void initTexture (const glw::Functions& gl) const; 270 271 EGLenum m_source; 272}; 273 274void TextureCubeMapImageSource::initTexture (const glw::Functions& gl) const 275{ 276 // Specify mipmap level 0 for all faces 277 static const GLenum faces[] = 278 { 279 GL_TEXTURE_CUBE_MAP_POSITIVE_X, 280 GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 281 GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 282 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 283 GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 284 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 285 }; 286 287 for (int faceNdx = 0; faceNdx < DE_LENGTH_OF_ARRAY(faces); faceNdx++) 288 GLU_CHECK_GLW_CALL(gl, texImage2D(faces[faceNdx], 0, m_format, IMAGE_WIDTH, IMAGE_HEIGHT, 0, m_format, m_type, DE_NULL)); 289} 290 291class RenderbufferClientBuffer : public GLClientBuffer 292{ 293public: 294 RenderbufferClientBuffer (const glw::Functions& gl) : m_rbo (gl) {} 295 GLuint getName (void) const { return *m_rbo; } 296 297private: 298 glu::Renderbuffer m_rbo; 299}; 300 301class RenderbufferImageSource : public GLImageSource 302{ 303public: 304 RenderbufferImageSource (GLenum format) : m_format(format) {} 305 306 string getRequiredExtension (void) const { return "EGL_KHR_gl_renderbuffer_image"; } 307 MovePtr<ClientBuffer> createBuffer (const glw::Functions& gl, Texture2D* reference) const; 308 GLenum getFormat (void) const { return m_format; } 309 310protected: 311 EGLenum getSource (void) const { return EGL_GL_RENDERBUFFER_KHR; } 312 AttribMap getCreateAttribs (void) const { return AttribMap(); } 313 314 GLenum m_format; 315}; 316 317void initializeStencilRbo(const glw::Functions& gl, GLuint rbo, Texture2D& ref) 318{ 319 static const deUint32 stencilValues[] = 320 { 321 0xBF688C11u, 322 0xB43D2922u, 323 0x055D5FFBu, 324 0x9300655Eu, 325 0x63BE0DF2u, 326 0x0345C13Bu, 327 0x1C184832u, 328 0xD107040Fu, 329 0x9B91569Fu, 330 0x0F0CFDC7u, 331 }; 332 333 GLU_CHECK_GLW_CALL(gl, framebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, 334 GL_RENDERBUFFER, rbo)); 335 GLU_CHECK_GLW_CALL(gl, clearStencil(0)); 336 GLU_CHECK_GLW_CALL(gl, clear(GL_STENCIL_BUFFER_BIT)); 337 tcu::clearStencil(ref.getLevel(0), 0); 338 339 // create a pattern 340 GLU_CHECK_GLW_CALL(gl, enable(GL_SCISSOR_TEST)); 341 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(stencilValues); ++ndx) 342 { 343 const tcu::IVec2 size = tcu::IVec2((int)((DE_LENGTH_OF_ARRAY(stencilValues) - ndx) * (ref.getWidth() / float(DE_LENGTH_OF_ARRAY(stencilValues)))), 344 (int)((DE_LENGTH_OF_ARRAY(stencilValues) - ndx) * (ref.getHeight() / float(DE_LENGTH_OF_ARRAY(stencilValues) + 4)))); // not symmetric 345 346 if (size.x() == 0 || size.y() == 0) 347 break; 348 349 GLU_CHECK_GLW_CALL(gl, scissor(0, 0, size.x(), size.y())); 350 GLU_CHECK_GLW_CALL(gl, clearStencil(stencilValues[ndx])); 351 GLU_CHECK_GLW_CALL(gl, clear(GL_STENCIL_BUFFER_BIT)); 352 353 tcu::clearStencil(tcu::getSubregion(ref.getLevel(0), 0, 0, size.x(), size.y()), stencilValues[ndx]); 354 } 355 356 GLU_CHECK_GLW_CALL(gl, disable(GL_SCISSOR_TEST)); 357 GLU_CHECK_GLW_CALL(gl, framebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, 358 GL_RENDERBUFFER, 0)); 359} 360 361void initializeDepthRbo(const glw::Functions& gl, GLuint rbo, Texture2D& ref) 362{ 363 const int NUM_STEPS = 13; 364 365 GLU_CHECK_GLW_CALL(gl, framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, 366 GL_RENDERBUFFER, rbo)); 367 368 GLU_CHECK_GLW_CALL(gl, clearDepthf(0.0f)); 369 GLU_CHECK_GLW_CALL(gl, clear(GL_DEPTH_BUFFER_BIT)); 370 tcu::clearDepth(ref.getLevel(0), 0.0f); 371 372 // create a pattern 373 GLU_CHECK_GLW_CALL(gl, enable(GL_SCISSOR_TEST)); 374 for (int ndx = 0; ndx < NUM_STEPS; ++ndx) 375 { 376 const float depth = ndx / float(NUM_STEPS); 377 const tcu::IVec2 size = tcu::IVec2((int)((NUM_STEPS - ndx) * (ref.getWidth() / float(NUM_STEPS))), 378 (int)((NUM_STEPS - ndx) * (ref.getHeight() / float(NUM_STEPS + 4)))); // not symmetric 379 380 if (size.x() == 0 || size.y() == 0) 381 break; 382 383 GLU_CHECK_GLW_CALL(gl, scissor(0, 0, size.x(), size.y())); 384 GLU_CHECK_GLW_CALL(gl, clearDepthf(depth)); 385 GLU_CHECK_GLW_CALL(gl, clear(GL_DEPTH_BUFFER_BIT)); 386 387 tcu::clearDepth(tcu::getSubregion(ref.getLevel(0), 0, 0, size.x(), size.y()), depth); 388 } 389 390 GLU_CHECK_GLW_CALL(gl, disable(GL_SCISSOR_TEST)); 391 GLU_CHECK_GLW_CALL(gl, framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, 392 GL_RENDERBUFFER, 0)); 393 394} 395 396void initializeColorRbo(const glw::Functions& gl, GLuint rbo, Texture2D& ref) 397{ 398 static const tcu::Vec4 colorValues[] = 399 { 400 tcu::Vec4(0.9f, 0.5f, 0.65f, 1.0f), 401 tcu::Vec4(0.5f, 0.7f, 0.65f, 1.0f), 402 tcu::Vec4(0.2f, 0.5f, 0.65f, 1.0f), 403 tcu::Vec4(0.3f, 0.1f, 0.5f, 1.0f), 404 tcu::Vec4(0.8f, 0.2f, 0.3f, 1.0f), 405 tcu::Vec4(0.9f, 0.4f, 0.8f, 1.0f), 406 }; 407 408 GLU_CHECK_GLW_CALL(gl, framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, 409 GL_RENDERBUFFER, rbo)); 410 GLU_CHECK_GLW_CALL(gl, clearColor(1.0f, 1.0f, 0.0f, 1.0f)); 411 GLU_CHECK_GLW_CALL(gl, clear(GL_COLOR_BUFFER_BIT)); 412 tcu::clear(ref.getLevel(0), Vec4(1.0f, 1.0f, 0.0f, 1.0f)); 413 414 // create a pattern 415 GLU_CHECK_GLW_CALL(gl, enable(GL_SCISSOR_TEST)); 416 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(colorValues); ++ndx) 417 { 418 const tcu::IVec2 size = tcu::IVec2((int)((DE_LENGTH_OF_ARRAY(colorValues) - ndx) * (ref.getWidth() / float(DE_LENGTH_OF_ARRAY(colorValues)))), 419 (int)((DE_LENGTH_OF_ARRAY(colorValues) - ndx) * (ref.getHeight() / float(DE_LENGTH_OF_ARRAY(colorValues) + 4)))); // not symmetric 420 421 if (size.x() == 0 || size.y() == 0) 422 break; 423 424 GLU_CHECK_GLW_CALL(gl, scissor(0, 0, size.x(), size.y())); 425 GLU_CHECK_GLW_CALL(gl, clearColor(colorValues[ndx].x(), colorValues[ndx].y(), colorValues[ndx].z(), colorValues[ndx].w())); 426 GLU_CHECK_GLW_CALL(gl, clear(GL_COLOR_BUFFER_BIT)); 427 428 tcu::clear(tcu::getSubregion(ref.getLevel(0), 0, 0, size.x(), size.y()), colorValues[ndx]); 429 } 430 431 GLU_CHECK_GLW_CALL(gl, disable(GL_SCISSOR_TEST)); 432 GLU_CHECK_GLW_CALL(gl, framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, 433 GL_RENDERBUFFER, 0)); 434} 435 436MovePtr<ClientBuffer> RenderbufferImageSource::createBuffer (const glw::Functions& gl, Texture2D* ref) const 437{ 438 MovePtr<RenderbufferClientBuffer> buffer (new RenderbufferClientBuffer(gl)); 439 const GLuint rbo = buffer->getName(); 440 441 GLU_CHECK_CALL_ERROR(gl.bindRenderbuffer(GL_RENDERBUFFER, rbo), gl.getError()); 442 443 // Specify storage. 444 GLU_CHECK_CALL_ERROR(gl.renderbufferStorage(GL_RENDERBUFFER, m_format, 64, 64), gl.getError()); 445 446 if (ref != DE_NULL) 447 { 448 Framebuffer fbo (gl); 449 const TextureFormat texFormat = glu::mapGLInternalFormat(m_format); 450 451 *ref = tcu::Texture2D(texFormat, 64, 64); 452 ref->allocLevel(0); 453 454 gl.bindFramebuffer(GL_FRAMEBUFFER, *fbo); 455 switch (m_format) 456 { 457 case GL_STENCIL_INDEX8: 458 initializeStencilRbo(gl, rbo, *ref); 459 break; 460 case GL_DEPTH_COMPONENT16: 461 initializeDepthRbo(gl, rbo, *ref); 462 break; 463 case GL_RGBA4: 464 initializeColorRbo(gl, rbo, *ref); 465 break; 466 case GL_RGB5_A1: 467 initializeColorRbo(gl, rbo, *ref); 468 break; 469 case GL_RGB565: 470 initializeColorRbo(gl, rbo, *ref); 471 break; 472 default: 473 DE_ASSERT(!"Impossible"); 474 } 475 476 gl.bindFramebuffer(GL_FRAMEBUFFER, 0); 477 } 478 479 return MovePtr<ClientBuffer>(buffer); 480} 481 482class UnsupportedImageSource : public ImageSource 483{ 484public: 485 UnsupportedImageSource (const string& message, GLenum format) : m_message(message), m_format(format) {} 486 string getRequiredExtension (void) const { fail(); return ""; } 487 MovePtr<ClientBuffer> createBuffer (const glw::Functions&, tcu::Texture2D*) const { fail(); return de::MovePtr<ClientBuffer>(); } 488 EGLImageKHR createImage (const Library& egl, EGLDisplay dpy, EGLContext ctx, EGLClientBuffer clientBuffer) const; 489 GLenum getFormat (void) const { return m_format; } 490 491private: 492 const string m_message; 493 GLenum m_format; 494 495 void fail (void) const { TCU_THROW(NotSupportedError, m_message.c_str()); } 496}; 497 498EGLImageKHR UnsupportedImageSource::createImage (const Library&, EGLDisplay, EGLContext, EGLClientBuffer) const 499{ 500 fail(); 501 return EGL_NO_IMAGE_KHR; 502} 503 504MovePtr<ImageSource> createTextureImageSource (EGLenum source, GLenum format, GLenum type, bool useTexLevel0) 505{ 506 if (source == EGL_GL_TEXTURE_2D_KHR) 507 return MovePtr<ImageSource>(new Texture2DImageSource(format, type, useTexLevel0)); 508 else 509 return MovePtr<ImageSource>(new TextureCubeMapImageSource(source, format, type, useTexLevel0)); 510} 511 512MovePtr<ImageSource> createRenderbufferImageSource (GLenum format) 513{ 514 return MovePtr<ImageSource>(new RenderbufferImageSource(format)); 515} 516 517MovePtr<ImageSource> createUnsupportedImageSource (const string& message, GLenum format) 518{ 519 return MovePtr<ImageSource>(new UnsupportedImageSource(message, format)); 520} 521 522} // Image 523} // egl 524} // deqp 525