Cogs.Core
CapabilitiesGLES30.cpp
1#include "CapabilitiesGLES30.h"
2
3#include <sstream>
4#include <iterator>
5#include <algorithm>
6#include <cctype>
7#include <regex>
8
9#include "CommonGLES30.h"
10#include "FormatsGLES30.h"
11
12#include "Foundation/Logging/Logger.h"
13
14#ifdef __EMSCRIPTEN__
15#include <emscripten.h>
16#endif
17
18namespace
19{
20 static Cogs::Logging::Log logger = Cogs::Logging::getLogger("CapabilitiesGLES30");
21
22 void toUpper(std::string & string)
23 {
24 std::transform(string.begin(), string.end(), string.begin(), [](const char & c) { return (char)::toupper(c); });
25 }
26}
27
28void Cogs::CapabilitiesGLES30::initialize(bool isFullGL, bool useClipControl)
29{
30 isFullGL_ = isFullGL;
31
32 std::string vendor((const char *)glGetString(GL_VENDOR));
33 std::string renderer((const char *)glGetString(GL_RENDERER));
34
35 if (logStrings) {
36 LOG_DEBUG(logger, "GL_VERSION: %s", glGetString(GL_VERSION));
37 LOG_DEBUG(logger, "GL_VENDOR: %s", vendor.c_str());
38 LOG_DEBUG(logger, "GL_RENDERER: %s", renderer.c_str());
39 LOG_DEBUG(logger, "GL_SHADING_LANGUAGE_VERSION: %s", glGetString(GL_SHADING_LANGUAGE_VERSION));
40
41 }
42
43 const auto extensionsString = std::string((const char *)glGetString(GL_EXTENSIONS));
44 {
45 std::istringstream sstream(extensionsString);
46 extensions = std::unordered_set<std::string>(std::istream_iterator<std::string>(sstream), std::istream_iterator<std::string>());
47 }
48
49 if (logExtensions) {
50 std::istringstream sstream(extensionsString);
51 std::string ext;
52 while(sstream >> ext){
53 LOG_DEBUG(logger, "Extension: %s", ext.c_str());
54 }
55 }
56
57 std::string unmaskedVendor;
58 std::string unmaskedRenderer;
59 if (isSupported("GL_WEBGL_debug_renderer_info")) {
60 unmaskedVendor = std::string((const char*)glGetString(0x9245)); // GL_UNMASKED_VENDOR_WEBGL
61 unmaskedRenderer = std::string((const char*)glGetString(0x9246)); // GL_UNMASKED_RENDERER_WEBGL
62 LOG_DEBUG(logger, "GL_UNMASKED_VENDOR_WEBGL: %s", unmaskedRenderer.c_str());
63 LOG_DEBUG(logger, "GL_UNMASKED_RENDERER_WEBGL: %s", unmaskedRenderer.c_str());
64 }
65 ::toUpper(unmaskedVendor);
66 ::toUpper(unmaskedRenderer);
67
68 ::toUpper(vendor);
69 ::toUpper(renderer);
70
71 if (vendor.find("NVIDIA") != vendor.npos) {
72 this->vendor = Vendors::nVidia;
73
74 if (renderer.find("QUADRO FX") != std::string::npos) series = Series::QuadroFX;
75 else if (renderer.find("QUADRO") != std::string::npos) series = Series::Quadro;
76 else if (renderer.find("GEFORCE") != std::string::npos) series = Series::geForce;
77
78 auto modelString = renderer.substr(0, renderer.find_first_of('/'));
79
80 if (modelString.size()) {
81 std::regex numbers("\\d.*");
82 std::smatch results;
83
84 if (std::regex_search(modelString, results, numbers)) {
85 model = std::stoi(results[0].str());
86 }
87 }
88 } else if (vendor.find("AMD") != vendor.npos || vendor.find("ATI") != vendor.npos) {
89 this->vendor = Vendors::AMD;
90
91 if (renderer.find("FIREGL") != std::string::npos) series = Series::FireGL;
92 } else if (vendor.find("INTEL") != vendor.npos) {
93 this->vendor = Vendors::Intel;
94 } else {
95 this->vendor = Vendors::Unknown;
96 }
97
98 glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &deviceCapabilities.MaxTextureSlots);
99 glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &deviceCapabilities.MaxVertexInputElements);
100
101 if (isSupported("GL_EXT_texture_filter_anisotropic")) {
102 glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &deviceCapabilities.MaxAnisotropy);
103 LOG_DEBUG(logger, "GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT: %f", deviceCapabilities.MaxAnisotropy);
104 }
105
106 GLint samples = 0;
107 glGetIntegerv(GL_MAX_SAMPLES, &samples);
108 deviceCapabilities.MaxSamples = std::max(1, samples);
109
110 // multisampling to offscreen buffers is broken in Mali-G72
111 if (renderer.find("MALI-G72") != std::string::npos || unmaskedRenderer.find("MALI-G72") != std::string::npos) {
112 LOG_DEBUG(logger, "Mali-G72 detected disabling multisampling");
113 deviceCapabilities.MaxSamples = 1;
114 }
115
116 GLint maxTextureSize = 0;
117 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
118 deviceCapabilities.MaxTexture2DSize = std::max(1, maxTextureSize);
119
120 GLint max3DTextureSize = 0;
121 glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &max3DTextureSize);
122 deviceCapabilities.MaxTexture3DSize = std::max(1, max3DTextureSize);
123
124 GLint maxCubeTextureSize = 0;
125 glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &maxCubeTextureSize);
126 deviceCapabilities.MaxTextureCubeSize = std::max(1, maxCubeTextureSize);
127
128 GLint maxArrayTextureLayers = 0;
129 glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &maxArrayTextureLayers);
130 deviceCapabilities.MaxTextureArrayLayers = std::max(1, maxArrayTextureLayers);
131
132 LOG_DEBUG(logger, "Texture limits: 2D=%u 3D=%u Cube=%u Array=%u",
133 deviceCapabilities.MaxTexture2DSize,
134 deviceCapabilities.MaxTexture3DSize,
135 deviceCapabilities.MaxTextureCubeSize,
136 deviceCapabilities.MaxTextureArrayLayers);
137
138 GLint uniformBufferOffsetAlignment = 0;
139 glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &uniformBufferOffsetAlignment);
140 if (uniformBufferOffsetAlignment) {
141 deviceCapabilities.ConstantBufferOffsetAlignment = uniformBufferOffsetAlignment;
142 }
143 deviceCapabilities.ConstantBufferRange = true;
144
145 if (isSupported("GL_OCULUS_multiview")) {
146 deviceCapabilities.MultiSampleMultiView = true;
147 deviceCapabilities.MultiView = true;
148 }
149 else if (isSupported("GL_OVR_multiview_multisampled_render_to_texture")) {
150 deviceCapabilities.MultiSampleMultiView = true;
151 deviceCapabilities.MultiView = true;
152 }
153 else if (isSupported("GL_OVR_multiview2")) {
154 deviceCapabilities.MultiView = true;
155 }
156 else if (isSupported("GL_OVR_multiview")) {
157 deviceCapabilities.MultiView = true;
158 }
159
160#ifdef __EMSCRIPTEN__
161 if (!deviceCapabilities.MultiView) {
162 int x = EM_ASM_INT({
163 for (const item of Object.values(Module.GL.contexts)) {
164 if (item && item.hasOwnProperty('GLctx')) {
165 const ext = item.GLctx.getExtension("OVR_multiview2");
166 return ext !== null ? 1 : 0;
167 }
168 }
169 });
170 if (x) {
171 LOG_DEBUG(logger, "Browser supports OVR_multiview2 even though emscripten doesn't, enabling regardless");
172 deviceCapabilities.MultiView = true;
173 }
174 }
175
176 if (!deviceCapabilities.MultiSampleMultiView) {
177 int x = EM_ASM_INT({
178 for (const item of Object.values(Module.GL.contexts)) {
179 if (item && item.hasOwnProperty('GLctx')) {
180 const ext = item.GLctx.getExtension("OCULUS_multiview");
181 return ext !== null ? 1 : 0;
182 }
183 }
184 });
185 if (x) {
186 LOG_DEBUG(logger, "Browser supports OCULUS_multiview even though emscripten doesn't, enabling regardless");
187 deviceCapabilities.MultiSampleMultiView = true;
188 deviceCapabilities.MultiView = true;
189 }
190 }
191#endif
192
193 // Check color encoding of default framebuffer.
194 deviceCapabilities.DefaultColorTargetHasLinearEncoding = false;
195 {
196 GLint param = GL_INVALID_ENUM;
197 glBindFramebuffer(GL_FRAMEBUFFER, 0);
198 glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_BACK, GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING, &param);
199 switch (param) {
200 case GL_LINEAR:
201 LOG_DEBUG(logger, "Default render target has LINEAR encoding");
202 deviceCapabilities.DefaultColorTargetHasLinearEncoding = true;
203 break;
204 case GL_SRGB:
205 LOG_DEBUG(logger, "Default render target has SRGB encoding");
206 break;
207 default:
208 LOG_ERROR(logger, "glGetFramebufferAttachmentParameter returned unrecognized enum: #%04x", param);
209 break;
210 }
211 }
212
213 if (deviceCapabilities.MultiView) {
214 GLint maxViews = 0;
215 glGetIntegerv(GL_MAX_VIEWS_OVR, &maxViews);
216 deviceCapabilities.MaxMultiViews = std::max(0, maxViews);
217 LOG_DEBUG(logger, "MultiView rendering available, maxViews=%d, maxSamples=%d",
218 maxViews,
219 deviceCapabilities.MultiSampleMultiView ? deviceCapabilities.MaxSamples : 1);
220 }
221
222// "framebufferTextureMultisampleMultiviewOVR"
223
224#ifdef EMSCRIPTEN
225 // ES 2.0 supports buffer sharing, WebGL explicitly does not (WebGL 1.0, section 6.1).
226 deviceCapabilities.VertexAndIndexDataInSharedBuffers = false;
227#endif
228
229 deviceCapabilities.SyncObjects = true;
230 deviceCapabilities.UnsignedIntIndexes = true;
231 deviceCapabilities.FloatTextures = true;
232 deviceCapabilities.FragDepth = true;
233 deviceCapabilities.SupportsHlsl = false;
234 deviceCapabilities.StartInstance = false;
235 deviceCapabilities.IndependentSamplerState = false;
236 deviceCapabilities.SupportsMultipleThreads = false;
237 deviceCapabilities.TextureCubeArrays = false;
238 deviceCapabilities.VertexArrayObjects = true;
239 deviceCapabilities.OriginOnTop = false;
240 deviceCapabilities.DepthNegativeOneToOne = !useClipControl;
241
242 if (isSupported("GL_EXT_depth_clamp")) {
243 // Disabled until we have control over its use in Cogs.Core: It will break
244 // reflection passes if it is enabled during it as that technique relies
245 // on using the near-plane clip to remove anything above the reflection
246 // plane.
247 // deviceCapabilities.NoDepthClip = true;
248 }
249 if (isSupported("GL_EXT_texture_compression_s3tc") ||
250 isSupported("GL_WEBGL_compressed_texture_s3tc")) {
251 deviceCapabilities.TextureCompressionS3TC = true;
252 }
253 if (isSupported("GL_ARB_texture_compression_rgtc") ||
254 isSupported("GL_EXT_texture_compression_rgtc")) {
255 deviceCapabilities.TextureCompressionRGTC = true;
256 }
257 if (isSupported("GL_ARB_texture_compression_bptc") ||
258 isSupported("GL_EXT_texture_compression_bptc")) {
259 deviceCapabilities.TextureCompressionBPTC = true;
260 }
261 if (isSupported("WEBGL_compressed_texture_etc") ||
262 isSupported("GL_OES_compressed_ETC1_RGB8_texture")) {
263 deviceCapabilities.TextureCompressionETC = true;
264 }
265 if (isSupported("WEBGL_compressed_texture_pvrtc") ||
266 isSupported("GL_IMG_texture_compression_pvrtc")) {
267 deviceCapabilities.TextureCompressionPVRTC = true;
268 }
269 if (isSupported("WEBGL_compressed_texture_astc") ||
270 isSupported("GL_OES_texture_compression_astc") || (
271 isSupported("GL_KHR_texture_compression_astc_hdr") &&
272 isSupported("GL_KHR_texture_compression_astc_ldr"))) {
273 deviceCapabilities.TextureCompressionASTC = true;
274 }
275
276 OpenGLES30::enableExtensionFormats(this);
277}
278
279bool Cogs::CapabilitiesGLES30::isSupported(const StringView & extension) const
280{
281 return extensions.find(std::string(extension)) != extensions.end();
282}
Log implementation class.
Definition: LogManager.h:140
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:181
uint32_t MaxTexture3DSize
Using D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION as default.
Definition: ICapabilities.h:81
uint32_t MaxTexture2DSize
Using D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION as default.
Definition: ICapabilities.h:80
uint32_t MaxTextureCubeSize
Using D3D11_REQ_TEXTURECUBE_DIMENSION as default.
Definition: ICapabilities.h:82
uint32_t MaxTextureArrayLayers
Using D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION as default.
Definition: ICapabilities.h:83
unsigned ConstantBufferOffsetAlignment
Minimum offset alignment when binding constant buffers.
Definition: ICapabilities.h:78
bool ConstantBufferRange
supports binding a range of a constant buffer.
Definition: ICapabilities.h:90
@ QuadroFX
nVidia Quadro FX professional graphics adapters.
Definition: ICapabilities.h:50
@ FireGL
AMD FireGL series.
Definition: ICapabilities.h:43
@ geForce
nVidia geForce consumer adapters.
Definition: ICapabilities.h:46
@ Quadro
nVidia Quadro professional graphics adapters.
Definition: ICapabilities.h:48
@ nVidia
nVidia Corporation.
Definition: ICapabilities.h:20
@ Unknown
Unknown device vendor.
Definition: ICapabilities.h:16