/*------------------------------------------------------------------------- * drawElements Quality Program Tester Core * ---------------------------------------- * * Copyright 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *//*! * \file * \brief WGL Utilities. *//*--------------------------------------------------------------------*/ #include "tcuWGL.hpp" #include "tcuWin32Window.hpp" #include "deDynamicLibrary.hpp" #include "deMemory.h" #include "deStringUtil.hpp" #include "tcuFormatUtil.hpp" #include "gluRenderConfig.hpp" #include <WinGDI.h> // WGL_ARB_pixel_format #define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000 #define WGL_DRAW_TO_WINDOW_ARB 0x2001 #define WGL_DRAW_TO_BITMAP_ARB 0x2002 #define WGL_ACCELERATION_ARB 0x2003 #define WGL_NEED_PALETTE_ARB 0x2004 #define WGL_NEED_SYSTEM_PALETTE_ARB 0x2005 #define WGL_SWAP_LAYER_BUFFERS_ARB 0x2006 #define WGL_SWAP_METHOD_ARB 0x2007 #define WGL_NUMBER_OVERLAYS_ARB 0x2008 #define WGL_NUMBER_UNDERLAYS_ARB 0x2009 #define WGL_TRANSPARENT_ARB 0x200A #define WGL_TRANSPARENT_RED_VALUE_ARB 0x2037 #define WGL_TRANSPARENT_GREEN_VALUE_ARB 0x2038 #define WGL_TRANSPARENT_BLUE_VALUE_ARB 0x2039 #define WGL_TRANSPARENT_ALPHA_VALUE_ARB 0x203A #define WGL_TRANSPARENT_INDEX_VALUE_ARB 0x203B #define WGL_SHARE_DEPTH_ARB 0x200C #define WGL_SHARE_STENCIL_ARB 0x200D #define WGL_SHARE_ACCUM_ARB 0x200E #define WGL_SUPPORT_GDI_ARB 0x200F #define WGL_SUPPORT_OPENGL_ARB 0x2010 #define WGL_DOUBLE_BUFFER_ARB 0x2011 #define WGL_STEREO_ARB 0x2012 #define WGL_PIXEL_TYPE_ARB 0x2013 #define WGL_COLOR_BITS_ARB 0x2014 #define WGL_RED_BITS_ARB 0x2015 #define WGL_RED_SHIFT_ARB 0x2016 #define WGL_GREEN_BITS_ARB 0x2017 #define WGL_GREEN_SHIFT_ARB 0x2018 #define WGL_BLUE_BITS_ARB 0x2019 #define WGL_BLUE_SHIFT_ARB 0x201A #define WGL_ALPHA_BITS_ARB 0x201B #define WGL_ALPHA_SHIFT_ARB 0x201C #define WGL_ACCUM_BITS_ARB 0x201D #define WGL_ACCUM_RED_BITS_ARB 0x201E #define WGL_ACCUM_GREEN_BITS_ARB 0x201F #define WGL_ACCUM_BLUE_BITS_ARB 0x2020 #define WGL_ACCUM_ALPHA_BITS_ARB 0x2021 #define WGL_DEPTH_BITS_ARB 0x2022 #define WGL_STENCIL_BITS_ARB 0x2023 #define WGL_AUX_BUFFERS_ARB 0x2024 #define WGL_NO_ACCELERATION_ARB 0x2025 #define WGL_GENERIC_ACCELERATION_ARB 0x2026 #define WGL_FULL_ACCELERATION_ARB 0x2027 #define WGL_TYPE_RGBA_ARB 0x202B #define WGL_TYPE_COLORINDEX_ARB 0x202C // WGL_ARB_color_buffer_float #define WGL_TYPE_RGBA_FLOAT_ARB 0x21A0 // WGL_EXT_pixel_type_packed_float #define WGL_TYPE_RGBA_UNSIGNED_FLOAT_EXT 0x20A8 // WGL_ARB_multisample #define WGL_SAMPLE_BUFFERS_ARB 0x2041 #define WGL_SAMPLES_ARB 0x2042 // WGL_ARB_create_context #define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 #define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 #define WGL_CONTEXT_LAYER_PLANE_ARB 0x2093 #define WGL_CONTEXT_FLAGS_ARB 0x2094 #define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 #define WGL_CONTEXT_DEBUG_BIT_ARB 0x0001 #define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002 #define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 #define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 #define WGL_CONTEXT_ES_PROFILE_BIT_EXT 0x00000004 // WGL_ARB_create_context_robustness #define WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x0004 #define WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 #define WGL_NO_RESET_NOTIFICATION_ARB 0x8261 #define WGL_LOSE_CONTEXT_ON_RESET_ARB 0x8252 DE_BEGIN_EXTERN_C // WGL core typedef HGLRC (WINAPI* wglCreateContextFunc) (HDC hdc); typedef BOOL (WINAPI* wglDeleteContextFunc) (HGLRC hglrc); typedef BOOL (WINAPI* wglMakeCurrentFunc) (HDC hdc, HGLRC hglrc); typedef PROC (WINAPI* wglGetProcAddressFunc) (LPCSTR lpszProc); typedef BOOL (WINAPI* wglSwapLayerBuffersFunc) (HDC dhc, UINT fuPlanes); // WGL_ARB_pixel_format typedef BOOL (WINAPI* wglGetPixelFormatAttribivARBFunc) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, int *piValues); typedef BOOL (WINAPI* wglGetPixelFormatAttribfvARBFunc) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, FLOAT *pfValues); typedef BOOL (WINAPI* wglChoosePixelFormatARBFunc) (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); // WGL_ARB_create_context typedef HGLRC (WINAPI* wglCreateContextAttribsARBFunc) (HDC hdc, HGLRC hshareContext, const int* attribList); DE_END_EXTERN_C namespace tcu { namespace wgl { // Functions struct Functions { // Core wglCreateContextFunc createContext; wglDeleteContextFunc deleteContext; wglMakeCurrentFunc makeCurrent; wglGetProcAddressFunc getProcAddress; wglSwapLayerBuffersFunc swapLayerBuffers; // WGL_ARB_pixel_format wglGetPixelFormatAttribivARBFunc getPixelFormatAttribivARB; wglGetPixelFormatAttribfvARBFunc getPixelFormatAttribfvARB; wglChoosePixelFormatARBFunc choosePixelFormatARB; // WGL_ARB_create_context wglCreateContextAttribsARBFunc createContextAttribsARB; Functions (void) : createContext (DE_NULL) , deleteContext (DE_NULL) , makeCurrent (DE_NULL) , getProcAddress (DE_NULL) , swapLayerBuffers (DE_NULL) , getPixelFormatAttribivARB (DE_NULL) , getPixelFormatAttribfvARB (DE_NULL) , choosePixelFormatARB (DE_NULL) , createContextAttribsARB (DE_NULL) { } }; // Library class Library { public: Library (HINSTANCE instance); ~Library (void); const Functions& getFunctions (void) const { return m_functions; } const de::DynamicLibrary& getGLLibrary (void) const { return m_library; } private: de::DynamicLibrary m_library; Functions m_functions; }; Library::Library (HINSTANCE instance) : m_library("opengl32.dll") { // Temporary 1x1 window for creating context win32::Window tmpWindow(instance, 1, 1); // Load WGL core. m_functions.createContext = (wglCreateContextFunc) m_library.getFunction("wglCreateContext"); m_functions.deleteContext = (wglDeleteContextFunc) m_library.getFunction("wglDeleteContext"); m_functions.getProcAddress = (wglGetProcAddressFunc) m_library.getFunction("wglGetProcAddress"); m_functions.makeCurrent = (wglMakeCurrentFunc) m_library.getFunction("wglMakeCurrent"); m_functions.swapLayerBuffers = (wglSwapLayerBuffersFunc) m_library.getFunction("wglSwapLayerBuffers"); if (!m_functions.createContext || !m_functions.deleteContext || !m_functions.getProcAddress || !m_functions.makeCurrent || !m_functions.swapLayerBuffers) throw ResourceError("Failed to load core WGL functions"); { PIXELFORMATDESCRIPTOR pixelFormatDesc; deMemset(&pixelFormatDesc, 0, sizeof(pixelFormatDesc)); pixelFormatDesc.nSize = sizeof(pixelFormatDesc); pixelFormatDesc.nVersion = 1; pixelFormatDesc.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; pixelFormatDesc.iPixelType = PFD_TYPE_RGBA; pixelFormatDesc.iLayerType = PFD_MAIN_PLANE; int pixelFormat = ChoosePixelFormat(tmpWindow.getDeviceContext(), &pixelFormatDesc); if (!SetPixelFormat(tmpWindow.getDeviceContext(), pixelFormat, &pixelFormatDesc)) throw ResourceError("Failed to set pixel format for temporary context creation"); } // Create temporary context for loading extension functions. HGLRC tmpCtx = m_functions.createContext(tmpWindow.getDeviceContext()); if (!tmpCtx || !m_functions.makeCurrent(tmpWindow.getDeviceContext(), tmpCtx)) { if (tmpCtx) m_functions.deleteContext(tmpCtx); throw ResourceError("Failed to create temporary WGL context"); } // WGL_ARB_pixel_format m_functions.getPixelFormatAttribivARB = (wglGetPixelFormatAttribivARBFunc)m_functions.getProcAddress("wglGetPixelFormatAttribivARB"); m_functions.getPixelFormatAttribfvARB = (wglGetPixelFormatAttribfvARBFunc)m_functions.getProcAddress("wglGetPixelFormatAttribfvARB"); m_functions.choosePixelFormatARB = (wglChoosePixelFormatARBFunc)m_functions.getProcAddress("wglChoosePixelFormatARB"); // WGL_ARB_create_context m_functions.createContextAttribsARB = (wglCreateContextAttribsARBFunc)m_functions.getProcAddress("wglCreateContextAttribsARB"); m_functions.makeCurrent(tmpWindow.getDeviceContext(), NULL); m_functions.deleteContext(tmpCtx); if (!m_functions.getPixelFormatAttribivARB || !m_functions.getPixelFormatAttribfvARB || !m_functions.choosePixelFormatARB || !m_functions.createContextAttribsARB) throw ResourceError("Failed to load WGL extension functions"); } Library::~Library (void) { } // Core Core::Core (HINSTANCE instance) : m_library(new Library(instance)) { } Core::~Core (void) { delete m_library; } std::vector<int> Core::getPixelFormats (HDC deviceCtx) const { const Functions& wgl = m_library->getFunctions(); int attribs[] = { WGL_NUMBER_PIXEL_FORMATS_ARB }; int values[DE_LENGTH_OF_ARRAY(attribs)]; if (!wgl.getPixelFormatAttribivARB(deviceCtx, 0, 0, DE_LENGTH_OF_ARRAY(attribs), &attribs[0], &values[0])) throw ResourceError("Failed to query number of WGL pixel formats"); // \todo [2013-04-14 pyry] Do we need to filter values at all? std::vector<int> pixelFormats(values[0]); for (int i = 0; i < values[0]; i++) pixelFormats[i] = i+1; return pixelFormats; } static PixelFormatInfo::Acceleration translateAcceleration (int accel) { switch (accel) { case WGL_NO_ACCELERATION_ARB: return PixelFormatInfo::ACCELERATION_NONE; case WGL_GENERIC_ACCELERATION_ARB: return PixelFormatInfo::ACCELERATION_GENERIC; case WGL_FULL_ACCELERATION_ARB: return PixelFormatInfo::ACCELERATION_FULL; default: return PixelFormatInfo::ACCELERATION_UNKNOWN; } } static PixelFormatInfo::PixelType translatePixelType (int type) { switch (type) { case WGL_TYPE_RGBA_ARB: return PixelFormatInfo::PIXELTYPE_RGBA; case WGL_TYPE_RGBA_FLOAT_ARB: return PixelFormatInfo::PIXELTYPE_RGBA_FLOAT; case WGL_TYPE_RGBA_UNSIGNED_FLOAT_EXT: return PixelFormatInfo::PIXELTYPE_RGBA_UNSIGNED_FLOAT; case WGL_TYPE_COLORINDEX_ARB: return PixelFormatInfo::PIXELTYPE_COLOR_INDEX; default: return PixelFormatInfo::PIXELTYPE_UNKNOWN; } } PixelFormatInfo Core::getPixelFormatInfo (HDC deviceCtx, int pixelFormat) const { const Functions& wgl = m_library->getFunctions(); int attribs [14]; int values [DE_LENGTH_OF_ARRAY(attribs)]; attribs[0] = WGL_DRAW_TO_WINDOW_ARB; attribs[1] = WGL_DRAW_TO_BITMAP_ARB; attribs[2] = WGL_ACCELERATION_ARB; attribs[3] = WGL_SUPPORT_OPENGL_ARB; attribs[4] = WGL_DOUBLE_BUFFER_ARB; attribs[5] = WGL_PIXEL_TYPE_ARB; attribs[6] = WGL_RED_BITS_ARB; attribs[7] = WGL_GREEN_BITS_ARB; attribs[8] = WGL_BLUE_BITS_ARB; attribs[9] = WGL_ALPHA_BITS_ARB; attribs[10] = WGL_DEPTH_BITS_ARB; attribs[11] = WGL_STENCIL_BITS_ARB; attribs[12] = WGL_SAMPLE_BUFFERS_ARB; attribs[13] = WGL_SAMPLES_ARB; deMemset(&values[0], 0, sizeof(values)); if (!wgl.getPixelFormatAttribivARB(deviceCtx, pixelFormat, 0, DE_LENGTH_OF_ARRAY(attribs), &attribs[0], &values[0])) throw ResourceError("Pixel format query failed"); // Translate values. PixelFormatInfo info; info.pixelFormat = pixelFormat; info.surfaceTypes |= (values[0] ? PixelFormatInfo::SURFACE_WINDOW : 0); info.surfaceTypes |= (values[1] ? PixelFormatInfo::SURFACE_PIXMAP : 0); info.acceleration = translateAcceleration(values[2]); info.supportOpenGL = values[3] != 0; info.doubleBuffer = values[4] != 0; info.pixelType = translatePixelType(values[5]); info.redBits = values[6]; info.greenBits = values[7]; info.blueBits = values[8]; info.alphaBits = values[9]; info.depthBits = values[10]; info.stencilBits = values[11]; info.sampleBuffers = values[12]; info.samples = values[13]; return info; } // Context Context::Context (const Core* core, HDC deviceCtx, glu::ContextType ctxType, int pixelFormat) : m_core (core) , m_deviceCtx (deviceCtx) , m_context (0) { const Functions& wgl = core->getLibrary()->getFunctions(); // Map context type & flags. int profileBit = 0; int flags = 0; switch (ctxType.getProfile()) { case glu::PROFILE_CORE: profileBit = WGL_CONTEXT_CORE_PROFILE_BIT_ARB; break; case glu::PROFILE_ES: profileBit = WGL_CONTEXT_ES_PROFILE_BIT_EXT; break; case glu::PROFILE_COMPATIBILITY: profileBit = WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; break; default: throw NotSupportedError("Unsupported context type for WGL"); } if ((ctxType.getFlags() & glu::CONTEXT_FORWARD_COMPATIBLE) != 0) flags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; if ((ctxType.getFlags() & glu::CONTEXT_DEBUG) != 0) flags |= WGL_CONTEXT_DEBUG_BIT_ARB; if ((ctxType.getFlags() & glu::CONTEXT_ROBUST) != 0) flags |= WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB; const int attribList[] = { WGL_CONTEXT_MAJOR_VERSION_ARB, ctxType.getMajorVersion(), WGL_CONTEXT_MINOR_VERSION_ARB, ctxType.getMinorVersion(), WGL_CONTEXT_PROFILE_MASK_ARB, profileBit, WGL_CONTEXT_FLAGS_ARB, flags, 0 }; // Set pixel format { PIXELFORMATDESCRIPTOR pixelFormatDesc; deMemset(&pixelFormatDesc, 0, sizeof(pixelFormatDesc)); if (!DescribePixelFormat(deviceCtx, pixelFormat, sizeof(pixelFormatDesc), &pixelFormatDesc)) throw ResourceError("DescribePixelFormat() failed"); if (!SetPixelFormat(deviceCtx, pixelFormat, &pixelFormatDesc)) throw ResourceError("Failed to set pixel format"); } // Create context m_context = wgl.createContextAttribsARB(deviceCtx, NULL, attribList); if (!m_context) throw ResourceError("Failed to create WGL context"); if (!wgl.makeCurrent(deviceCtx, m_context)) { wgl.deleteContext(m_context); throw ResourceError("wglMakeCurrent() failed"); } } Context::~Context (void) { const Functions& wgl = m_core->getLibrary()->getFunctions(); wgl.makeCurrent(m_deviceCtx, NULL); wgl.deleteContext(m_context); } FunctionPtr Context::getGLFunction (const char* name) const { FunctionPtr ptr = DE_NULL; // Try first with wglGeProcAddress() ptr = (FunctionPtr)m_core->getLibrary()->getFunctions().getProcAddress(name); // Fall-back to dynlib if (!ptr) ptr = (FunctionPtr)m_core->getLibrary()->getGLLibrary().getFunction(name); return ptr; } void Context::swapBuffers (void) const { const Functions& wgl = m_core->getLibrary()->getFunctions(); if (!wgl.swapLayerBuffers(m_deviceCtx, WGL_SWAP_MAIN_PLANE)) throw ResourceError("wglSwapBuffers() failed"); } int choosePixelFormat (const Core& wgl, HDC deviceCtx, const glu::RenderConfig& config) { std::vector<int> pixelFormats = wgl.getPixelFormats(deviceCtx); for (std::vector<int>::const_iterator fmtIter = pixelFormats.begin(); fmtIter != pixelFormats.end(); ++fmtIter) { PixelFormatInfo info = wgl.getPixelFormatInfo(deviceCtx, *fmtIter); // Base rules: Must be OpenGL-compatible, RGBA, double-buffered, and window-renderable if (!info.supportOpenGL || !(info.pixelType == wgl::PixelFormatInfo::PIXELTYPE_RGBA) || !info.doubleBuffer || !(info.surfaceTypes & wgl::PixelFormatInfo::SURFACE_WINDOW)) continue; if (config.redBits != glu::RenderConfig::DONT_CARE && config.redBits != info.redBits) continue; if (config.greenBits != glu::RenderConfig::DONT_CARE && config.greenBits != info.greenBits) continue; if (config.blueBits != glu::RenderConfig::DONT_CARE && config.blueBits != info.blueBits) continue; if (config.alphaBits != glu::RenderConfig::DONT_CARE && config.alphaBits != info.alphaBits) continue; if (config.depthBits != glu::RenderConfig::DONT_CARE && config.depthBits != info.depthBits) continue; if (config.stencilBits != glu::RenderConfig::DONT_CARE && config.stencilBits != info.stencilBits) continue; if (config.numSamples != glu::RenderConfig::DONT_CARE && config.numSamples != info.samples) continue; // Passed all tests - select this. return info.pixelFormat; } return -1; } } // wgl } // tcu