Sources/Toolkits/OpenGL/Query/GLUQuery.mm
/* |
File: GLUQuery.mm |
Abstract: |
Utility toolkit for constructing a query of OpenGL Core profile features. |
Version: 1.2 |
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple |
Inc. ("Apple") in consideration of your agreement to the following |
terms, and your use, installation, modification or redistribution of |
this Apple software constitutes acceptance of these terms. If you do |
not agree with these terms, please do not use, install, modify or |
redistribute this Apple software. |
In consideration of your agreement to abide by the following terms, and |
subject to these terms, Apple grants you a personal, non-exclusive |
license, under Apple's copyrights in this original Apple software (the |
"Apple Software"), to use, reproduce, modify and redistribute the Apple |
Software, with or without modifications, in source and/or binary forms; |
provided that if you redistribute the Apple Software in its entirety and |
without modifications, you must retain this notice and the following |
text and disclaimers in all such redistributions of the Apple Software. |
Neither the name, trademarks, service marks or logos of Apple Inc. may |
be used to endorse or promote products derived from the Apple Software |
without specific prior written permission from Apple. Except as |
expressly stated in this notice, no other rights or licenses, express or |
implied, are granted by Apple herein, including but not limited to any |
patent rights that may be infringed by your derivative works or by other |
works in which the Apple Software may be incorporated. |
The Apple Software is provided by Apple on an "AS IS" basis. APPLE |
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION |
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS |
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND |
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. |
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL |
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, |
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED |
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), |
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE |
POSSIBILITY OF SUCH DAMAGE. |
Copyright (C) 2014 Apple Inc. All Rights Reserved. |
*/ |
#pragma mark - |
#pragma mark Headers |
// STL containers |
#import <sstream> |
// Mac OS X OpenGL frameworks |
#import <OpenGL/OpenGL.h> |
#import <OpenGL/gl3.h> |
// OpenGL string utilities |
#import "GLUString.h" |
// Query Header |
#import "GLUQuery.h" |
#pragma mark - |
#pragma mark Private - Data Structures |
namespace GLU |
{ |
// Search string for feature family |
static const GLchar *kQueryStringApple = "GL_APPLE"; |
static const GLchar *kQueryStringARB = "GL_ARB"; |
static const GLchar *kQueryStringEXT = "GL_EXT"; |
// String feature family length |
static const size_t kQuerySzStringApple = 8; |
static const size_t kQuerySzStringARB = 6; |
static const size_t kQuerySzStringEXT = 6; |
// More (private) OpenGL container types |
typedef std::stringstream SStream; |
typedef std::unordered_map<String, String> ExtDB; |
typedef std::unordered_map<String, String>::iterator ExtDBitr; |
// Renderer, version, and vendor data structures |
struct QueryString |
{ |
String m_Renderer; |
String m_Version; |
String m_Vendor; |
}; |
typedef struct QueryString QueryString; |
// Apple, ARB, and EXT features and their strings |
struct QueryFeatures |
{ |
Features m_Apple; |
Features m_ARB; |
Features m_EXT; |
CFMutableArrayRef mpApple; |
CFMutableArrayRef mpARB; |
CFMutableArrayRef mpEXT; |
}; |
typedef struct QueryFeatures QueryFeatures; |
// Apple, ARB, and EXT features as an associative array |
struct QueryDB |
{ |
ExtDB m_Exts; |
ExtDBitr m_ExtsEnd; |
}; |
typedef struct QueryDB QueryDB; |
// OpenGL query strings, extensions (or features), including |
// a dictionary representation |
struct Query |
{ |
QueryString m_String; |
QueryFeatures m_Features; |
QueryDB m_DB; |
}; |
typedef struct Query Query; |
} // GLU |
#pragma mark - |
#pragma mark Private - Utilities - Strings |
// OpenGL features as a string, where each feature is separated |
// using a seperator string |
static GLU::String GLUQueryCreateStringFeatures(const GLU::String &rSeperator, |
const GLU::Features &rFeatures) |
{ |
GLU::String string; |
GLuint iMax = rFeatures.size(); |
if(iMax) |
{ |
GLuint i; |
GLU::SStream oss; |
GLU::String seperator = !rSeperator.empty() ? rSeperator : " "; |
iMax--; |
for(i = 0; i < iMax; ++i) |
{ |
oss << rFeatures[i] << seperator; |
} // for |
oss << rFeatures[iMax]; |
string = oss.str(); |
} // if |
return string; |
} // GLUQueryCreateStringFeatures |
// OpenGL Apple features as a string, where each feature is separated |
// using a seperator string |
static GLU::String GLUQueryCreateStringApple(const GLU::String &rSeperator, |
const GLU::QueryRef pQuery) |
{ |
return GLUQueryCreateStringFeatures(rSeperator, pQuery->m_Features.m_Apple); |
} // GLUQueryCreateStringApple |
// OpenGL ARB features as a string, where each feature is separated |
// using a seperator string |
static GLU::String GLUQueryCreateStringARB(const GLU::String &rSeperator, |
const GLU::QueryRef pQuery) |
{ |
return GLUQueryCreateStringFeatures(rSeperator, pQuery->m_Features.m_ARB); |
} // GLUQueryCreateStringARB |
// OpenGL EXT features as a string, where each feature is separated |
// using a seperator string |
static GLU::String GLUQueryCreateStringEXT(const GLU::String &rSeperator, |
const GLU::QueryRef pQuery) |
{ |
return GLUQueryCreateStringFeatures(rSeperator, pQuery->m_Features.m_EXT); |
} // GLUQueryCreateStringEXT |
#pragma mark - |
#pragma mark Private - Utilities - Arrays |
// Found Apple feature |
static bool GLUQueryStringIsApple(const GLchar * const pExtension) |
{ |
return(strncmp(pExtension, GLU::kQueryStringApple, GLU::kQuerySzStringApple) == 0); |
} // GLUQueryStringIsApple |
// Found ARB feature |
static bool GLUQueryStringIsARB(const GLchar * const pExtension) |
{ |
return(strncmp(pExtension, GLU::kQueryStringARB, GLU::kQuerySzStringARB) == 0); |
} // GLUQueryStringIsARB |
// Found EXT feature |
static bool GLUQueryStringIsEXT(const GLchar * const pExtension) |
{ |
return(strncmp(pExtension, GLU::kQueryStringEXT, GLU::kQuerySzStringEXT) == 0); |
} // GLUQueryStringIsEXT |
// Add Apple feature |
static void GLUQueryAddFeatureApple(const GLchar * const pFeature, |
GLU::QueryRef pQuery) |
{ |
GLU::String feature(pFeature); |
pQuery->m_Features.m_Apple.push_back(feature); |
pQuery->m_DB.m_Exts[feature] = GLU::kQueryStringApple; |
} // GLUQueryAddFeatureApple |
// Add ARB feature |
static void GLUQueryAddFeatureARB(const GLchar * const pFeature, |
GLU::QueryRef pQuery) |
{ |
GLU::String feature(pFeature); |
pQuery->m_Features.m_ARB.push_back(feature); |
pQuery->m_DB.m_Exts[feature] = GLU::kQueryStringARB; |
} // GLUQueryAddFeatureARB |
// Add EXT feature |
static void GLUQueryAddFeatureEXT(const GLchar * const pFeature, |
GLU::QueryRef pQuery) |
{ |
GLU::String feature(pFeature); |
pQuery->m_Features.m_EXT.push_back(feature); |
pQuery->m_DB.m_Exts[feature] = GLU::kQueryStringEXT; |
} // GLUQueryAddFeatureEXT |
// Query OpenGL and get a string representation of extension (or feature). |
static void GLUQueryAppendFeature(const GLuint &rExtIdx, |
GLU::QueryRef pQuery) |
{ |
const GLchar *pFeature = (const GLchar *)glGetStringi(GL_EXTENSIONS, rExtIdx); |
if(pFeature != nullptr) |
{ |
if(GLUQueryStringIsApple(pFeature)) |
{ |
GLUQueryAddFeatureApple(pFeature, pQuery); |
} // if |
else if(GLUQueryStringIsARB(pFeature)) |
{ |
GLUQueryAddFeatureARB(pFeature, pQuery); |
} // else if |
else if(GLUQueryStringIsEXT(pFeature)) |
{ |
GLUQueryAddFeatureEXT(pFeature, pQuery); |
} // else if |
} // if |
} // GLUQueryAppendFeature |
#pragma mark - |
#pragma mark Private - Utilities - Destructors |
// Clear all strings |
static void GLUQueryClearStrings(GLU::QueryRef pQuery) |
{ |
pQuery->m_String.m_Renderer.clear(); |
pQuery->m_String.m_Vendor.clear(); |
pQuery->m_String.m_Version.clear(); |
} // GLUQueryClearStrings |
// Clear all features |
static void GLUQueryClearFeatures(GLU::QueryRef pQuery) |
{ |
pQuery->m_Features.m_Apple.clear(); |
pQuery->m_Features.m_ARB.clear(); |
pQuery->m_Features.m_EXT.clear(); |
} // GLUQueryClearFeatures |
// Release all arrays |
static void GLUQueryReleaseArrays(GLU::QueryRef pQuery) |
{ |
if(pQuery->m_Features.mpApple != nullptr) |
{ |
CFRelease(pQuery->m_Features.mpApple); |
} // if |
if(pQuery->m_Features.mpARB != nullptr) |
{ |
CFRelease(pQuery->m_Features.mpARB); |
} // if |
if(pQuery->m_Features.mpEXT != nullptr) |
{ |
CFRelease(pQuery->m_Features.mpEXT); |
} // if |
} // GLUQueryReleaseArrays |
// Clear extensions' map |
static void GLUQueryClearDB(GLU::QueryRef pQuery) |
{ |
pQuery->m_DB.m_Exts.clear(); |
} // GLUQueryClearDB |
#pragma mark - |
#pragma mark Private - Utilities - Constructors |
// Create a vector of extensions (or features) |
static void GLUQueryCreateFeatures(GLU::QueryRef pQuery) |
{ |
GLuint nExtIdx = 0; |
GLint nExtCnt = 0; |
glGetIntegerv(GL_NUM_EXTENSIONS, &nExtCnt); |
for(nExtIdx = 0; nExtIdx < nExtCnt; ++nExtIdx) |
{ |
GLUQueryAppendFeature(nExtIdx, pQuery); |
} // for |
pQuery->m_DB.m_ExtsEnd = pQuery->m_DB.m_Exts.end(); |
pQuery->m_Features.mpApple = nullptr; |
pQuery->m_Features.mpARB = nullptr; |
pQuery->m_Features.mpEXT = nullptr; |
} // GLUQueryCreateFeatures |
// Create vendor, version, and renderer strings |
static void GLUQueryCreateStrings(GLU::QueryRef pQuery) |
{ |
pQuery->m_String.m_Renderer = GLU::StringCreateWithParam(GL_VERSION); |
pQuery->m_String.m_Vendor = GLU::StringCreateWithParam(GL_VENDOR); |
pQuery->m_String.m_Version = GLU::StringCreateWithParam(GL_RENDERER); |
} // GLUQueryCreateStrings |
#pragma mark - |
#pragma mark Private - Utilities - Features |
// Convert STL vector to CF mutable array |
static CFMutableArrayRef GLUQueryFeaturesCreateCopy(const GLU::Features &rFeature) |
{ |
CFMutableArrayRef pFeatures = nullptr; |
GLuint iMax = rFeature.size(); |
if(iMax) |
{ |
pFeatures = CFArrayCreateMutable(kCFAllocatorDefault, |
0, |
&kCFTypeArrayCallBacks); |
if(pFeatures != nullptr) |
{ |
CFStringRef pFeature = NULL; |
GLuint i; |
for(i = 0; i < iMax; ++i) |
{ |
pFeature = CFStringCreateWithCString(kCFAllocatorDefault, |
rFeature[i].c_str(), |
kCFStringEncodingASCII); |
if(pFeature != nullptr) |
{ |
CFArrayAppendValue(pFeatures, pFeature); |
CFRelease(pFeature); |
} // if |
} // for |
} // if |
} // if |
return pFeatures; |
} // GLUQueryFeaturesCreateCopy |
#pragma mark - |
#pragma mark Public - Constructor |
// Create an OpenGL query opaque data reference |
GLU::QueryRef GLU::QueryCreate() |
{ |
GLU::QueryRef pQuery = NULL; |
try |
{ |
pQuery = new GLU::Query; |
GLUQueryCreateFeatures(pQuery); |
GLUQueryCreateStrings(pQuery); |
} // try |
catch(std::bad_alloc& ba) |
{ |
NSLog(@">> ERROR: Failed allocating memory for OpenGL query object backing store: \"%s\"", ba.what()); |
} // catch |
return(pQuery); |
} // GLUQueryCreate |
#pragma mark - |
#pragma mark Public - Destructor |
// Delete an OpenGL query opaque data reference |
void GLU::QueryDelete(GLU::QueryRef pQuery) |
{ |
if(pQuery != nullptr) |
{ |
GLUQueryClearFeatures(pQuery); |
GLUQueryClearStrings(pQuery); |
GLUQueryClearDB(pQuery); |
GLUQueryReleaseArrays(pQuery); |
delete pQuery; |
} // if |
} // GLQueryDelete |
#pragma mark - |
#pragma mark Public - Accessors - Features |
// OpenGL Apple features |
const GLU::Features GLU::QueryFeaturesGetApple(const GLU::QueryRef pQuery) |
{ |
return (pQuery != nullptr) ? pQuery->m_Features.m_Apple : GLU::Features(1); |
} // GLU::QueryFeaturesGetApple |
// OpenGL ARB features |
const GLU::Features GLU::QueryFeaturesGetARB(const GLU::QueryRef pQuery) |
{ |
return (pQuery != nullptr) ? pQuery->m_Features.m_ARB : GLU::Features(1); |
} // GLU::QueryFeaturesGetARB |
// OpenGL EXT features |
const GLU::Features GLU::QueryFeaturesGetEXT(const GLU::QueryRef pQuery) |
{ |
return (pQuery != nullptr) ? pQuery->m_Features.m_EXT : GLU::Features(1); |
} // GLU::QueryFeaturesGetEXT |
#pragma mark - |
#pragma mark Public - Accessors - Strings |
// OpnGL vendor |
const GLU::String GLU::QueryStringGetVendor(const GLU::QueryRef pQuery) |
{ |
return (pQuery != nullptr) ? pQuery->m_String.m_Vendor : ""; |
} // GLU::QueryStringGetVendor |
// OpenGL version |
const GLU::String GLU::QueryStringGetVersion(const GLU::QueryRef pQuery) |
{ |
return (pQuery != nullptr) ? pQuery->m_String.m_Version : ""; |
} // GLU::QueryStringGetVersion |
// OpenGL renderer |
const GLU::String GLU::QueryStringGetRenderer(const GLU::QueryRef pQuery) |
{ |
return (pQuery != nullptr) ? pQuery->m_String.m_Renderer : ""; |
} // GLU::QueryStringGetRenderer |
// OpenGL Apple features as a string, where each feature |
// is separated using a seperator string |
const GLU::String GLU::QueryStringGetApple(const GLU::String &rSeperator, |
const GLU::QueryRef pQuery) |
{ |
return (pQuery != nullptr) ? GLUQueryCreateStringApple(rSeperator, pQuery) : ""; |
} // GLU::QueryStringGetApple |
// OpenGL Apple features as a string, where each feature |
// is separated using a seperator string |
const GLU::String GLU::QueryStringGetARB(const GLU::String &rSeperator, |
const GLU::QueryRef pQuery) |
{ |
return (pQuery != nullptr) ? GLUQueryCreateStringARB(rSeperator, pQuery) : ""; |
} // GLU::QueryStringGetARB |
// OpenGL Apple features as a string, where each feature |
// is separated using a seperator string |
const GLU::String GLU::QueryStringGetEXT(const GLU::String &rSeperator, |
const GLU::QueryRef pQuery) |
{ |
return (pQuery != nullptr) ? GLUQueryCreateStringEXT(rSeperator, pQuery) : ""; |
} // GLU::QueryStringGetEXT |
#pragma mark - |
#pragma mark Public - Utilities - Arrays |
// Apple feature set as an CF array |
CFArrayRef GLU::QueryArrayGetApple(GLU::QueryRef pQuery) |
{ |
if(pQuery->m_Features.mpApple == nullptr) |
{ |
pQuery->m_Features.mpApple = GLUQueryFeaturesCreateCopy(pQuery->m_Features.m_Apple); |
} // if |
return pQuery->m_Features.mpApple; |
} // GLQueryArrayGetApple |
// ARB feature set as an CF array |
CFArrayRef GLU::QueryArrayGetARB(GLU::QueryRef pQuery) |
{ |
if(pQuery->m_Features.mpARB == nullptr) |
{ |
pQuery->m_Features.mpARB = GLUQueryFeaturesCreateCopy(pQuery->m_Features.m_ARB); |
} // if |
return pQuery->m_Features.mpARB; |
} // GLQueryArrayGetARB |
// EXT feature set as an CF array |
CFArrayRef GLU::QueryArrayGetEXT(GLU::QueryRef pQuery) |
{ |
if(pQuery->m_Features.mpEXT == nullptr) |
{ |
pQuery->m_Features.mpEXT = GLUQueryFeaturesCreateCopy(pQuery->m_Features.m_EXT); |
} // if |
return pQuery->m_Features.mpEXT; |
} // GLQueryArrayGetEXT |
#pragma mark - |
#pragma mark Public - Utilities - Features |
// Is the feature available |
const bool GLU::QueryFeatureIsAvailable(const GLU::Feature &rFeature, |
GLU::QueryRef pQuery) |
{ |
return (pQuery != nullptr) ? pQuery->m_DB.m_Exts.find(rFeature) != pQuery->m_DB.m_ExtsEnd : false; |
} // GLQueryFeatureIsAvailable |
// If the feature is found, the returned string will be GL_APPLE, GL_ARB, or GL_EXT |
const GLU::String GLU::QueryFeatureGetType(const GLU::Feature &rFeature, |
GLU::QueryRef pQuery) |
{ |
return (pQuery != nullptr) ? pQuery->m_DB.m_Exts[rFeature] : ""; |
} // GLQueryFeatureGetType |
Copyright © 2014 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2014-10-16