mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
OpenGL: Add support for a few more OpenGL profiles
- 4.1 and 4.3 contexts can now be requested - The requested context version is no longer ignored on Linux - Debugging contexts are now enabled in Debug builds with GL 4.3 - Fixes a bug where glEnable(GL_TEXTURE_2D) was called in core profiles
This commit is contained in:
parent
ac6a455229
commit
02b5ab748a
8 changed files with 184 additions and 69 deletions
|
|
@ -240,6 +240,22 @@ private:
|
|||
OpenGLTargetSaver& operator= (const OpenGLTargetSaver&);
|
||||
};
|
||||
|
||||
static bool contextRequiresTexture2DEnableDisable()
|
||||
{
|
||||
#if JUCE_OPENGL_ES
|
||||
return false;
|
||||
#else
|
||||
clearGLError();
|
||||
GLint mask = 0;
|
||||
glGetIntegerv (GL_CONTEXT_PROFILE_MASK, &mask);
|
||||
|
||||
if (glGetError() == GL_INVALID_ENUM)
|
||||
return true;
|
||||
|
||||
return (mask & (GLint) GL_CONTEXT_CORE_PROFILE_BIT) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
|
||||
//==============================================================================
|
||||
|
|
|
|||
|
|
@ -72,24 +72,19 @@ public:
|
|||
|
||||
[((UIView*) peer->getNativeHandle()) addSubview: view];
|
||||
|
||||
if (version == openGL3_2 && [[UIDevice currentDevice].systemVersion floatValue] >= 7.0)
|
||||
{
|
||||
if (! createContext (kEAGLRenderingAPIOpenGLES3, contextToShare))
|
||||
{
|
||||
releaseContext();
|
||||
createContext (kEAGLRenderingAPIOpenGLES2, contextToShare);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
createContext (kEAGLRenderingAPIOpenGLES2, contextToShare);
|
||||
}
|
||||
const auto shouldUseES3 = version != defaultGLVersion
|
||||
&& [[UIDevice currentDevice].systemVersion floatValue] >= 7.0;
|
||||
|
||||
const auto gotContext = (shouldUseES3 && createContext (kEAGLRenderingAPIOpenGLES3, contextToShare))
|
||||
|| createContext (kEAGLRenderingAPIOpenGLES2, contextToShare);
|
||||
|
||||
jassertquiet (gotContext);
|
||||
|
||||
if (context != nil)
|
||||
{
|
||||
// I'd prefer to put this stuff in the initialiseOnRenderThread() call, but doing
|
||||
// so causes mysterious timing-related failures.
|
||||
[EAGLContext setCurrentContext: context];
|
||||
[EAGLContext setCurrentContext: context.get()];
|
||||
gl::loadFunctions();
|
||||
createGLBuffers();
|
||||
deactivateCurrentContext();
|
||||
|
|
@ -108,7 +103,7 @@ public:
|
|||
|
||||
~NativeContext()
|
||||
{
|
||||
releaseContext();
|
||||
context.reset();
|
||||
[view removeFromSuperview];
|
||||
[view release];
|
||||
}
|
||||
|
|
@ -123,12 +118,12 @@ public:
|
|||
}
|
||||
|
||||
bool createdOk() const noexcept { return getRawContext() != nullptr; }
|
||||
void* getRawContext() const noexcept { return context; }
|
||||
void* getRawContext() const noexcept { return context.get(); }
|
||||
GLuint getFrameBufferID() const noexcept { return useMSAA ? msaaBufferHandle : frameBufferHandle; }
|
||||
|
||||
bool makeActive() const noexcept
|
||||
{
|
||||
if (! [EAGLContext setCurrentContext: context])
|
||||
if (! [EAGLContext setCurrentContext: context.get()])
|
||||
return false;
|
||||
|
||||
glBindFramebuffer (GL_FRAMEBUFFER, useMSAA ? msaaBufferHandle
|
||||
|
|
@ -138,7 +133,7 @@ public:
|
|||
|
||||
bool isActive() const noexcept
|
||||
{
|
||||
return [EAGLContext currentContext] == context;
|
||||
return [EAGLContext currentContext] == context.get();
|
||||
}
|
||||
|
||||
static void deactivateCurrentContext()
|
||||
|
|
@ -170,7 +165,7 @@ public:
|
|||
}
|
||||
|
||||
glBindRenderbuffer (GL_RENDERBUFFER, colorBufferHandle);
|
||||
[context presentRenderbuffer: GL_RENDERBUFFER];
|
||||
[context.get() presentRenderbuffer: GL_RENDERBUFFER];
|
||||
|
||||
if (needToRebuildBuffers)
|
||||
{
|
||||
|
|
@ -209,7 +204,7 @@ private:
|
|||
Component& component;
|
||||
JuceGLView* view = nil;
|
||||
CAEAGLLayer* glLayer = nil;
|
||||
EAGLContext* context = nil;
|
||||
NSUniquePtr<EAGLContext> context;
|
||||
const OpenGLVersion openGLversion;
|
||||
const bool useDepthBuffer, useMSAA;
|
||||
|
||||
|
|
@ -223,21 +218,16 @@ private:
|
|||
bool createContext (EAGLRenderingAPI type, void* contextToShare)
|
||||
{
|
||||
jassert (context == nil);
|
||||
context = [EAGLContext alloc];
|
||||
context.reset ([EAGLContext alloc]);
|
||||
|
||||
context = contextToShare != nullptr
|
||||
? [context initWithAPI: type sharegroup: [(EAGLContext*) contextToShare sharegroup]]
|
||||
: [context initWithAPI: type];
|
||||
if (contextToShare != nullptr)
|
||||
[context.get() initWithAPI: type sharegroup: [(EAGLContext*) contextToShare sharegroup]];
|
||||
else
|
||||
[context.get() initWithAPI: type];
|
||||
|
||||
return context != nil;
|
||||
}
|
||||
|
||||
void releaseContext()
|
||||
{
|
||||
[context release];
|
||||
context = nil;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void createGLBuffers()
|
||||
{
|
||||
|
|
@ -249,7 +239,7 @@ private:
|
|||
|
||||
glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorBufferHandle);
|
||||
|
||||
bool ok = [context renderbufferStorage: GL_RENDERBUFFER fromDrawable: glLayer];
|
||||
bool ok = [context.get() renderbufferStorage: GL_RENDERBUFFER fromDrawable: glLayer];
|
||||
jassert (ok); ignoreUnused (ok);
|
||||
|
||||
GLint width, height;
|
||||
|
|
@ -289,7 +279,7 @@ private:
|
|||
void freeGLBuffers()
|
||||
{
|
||||
JUCE_CHECK_OPENGL_ERROR
|
||||
[context renderbufferStorage: GL_RENDERBUFFER fromDrawable: nil];
|
||||
[context.get() renderbufferStorage: GL_RENDERBUFFER fromDrawable: nil];
|
||||
|
||||
deleteFrameBuffer (frameBufferHandle);
|
||||
deleteFrameBuffer (msaaBufferHandle);
|
||||
|
|
|
|||
|
|
@ -28,6 +28,18 @@ namespace juce
|
|||
|
||||
extern XContext windowHandleXContext;
|
||||
|
||||
struct XFreeDeleter
|
||||
{
|
||||
void operator() (void* ptr) const
|
||||
{
|
||||
if (ptr != nullptr)
|
||||
X11Symbols::getInstance()->xFree (ptr);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Data>
|
||||
std::unique_ptr<Data, XFreeDeleter> makeXFreePtr (Data* raw) { return std::unique_ptr<Data, XFreeDeleter> (raw); }
|
||||
|
||||
//==============================================================================
|
||||
// Defined juce_linux_Windowing.cpp
|
||||
void juce_LinuxAddRepaintListener (ComponentPeer*, Component* dummy);
|
||||
|
|
@ -80,15 +92,15 @@ public:
|
|||
jassert (peer != nullptr);
|
||||
|
||||
auto windowH = (Window) peer->getNativeHandle();
|
||||
auto colourMap = X11Symbols::getInstance()->xCreateColormap (display, windowH, bestVisual->visual, AllocNone);
|
||||
auto visual = glXGetVisualFromFBConfig (display, *bestConfig);
|
||||
auto colourMap = X11Symbols::getInstance()->xCreateColormap (display, windowH, visual->visual, AllocNone);
|
||||
|
||||
XSetWindowAttributes swa;
|
||||
swa.colormap = colourMap;
|
||||
swa.border_pixel = 0;
|
||||
swa.event_mask = embeddedWindowEventMask;
|
||||
|
||||
auto glBounds = component.getTopLevelComponent()
|
||||
->getLocalArea (&component, component.getLocalBounds());
|
||||
auto glBounds = component.getTopLevelComponent()->getLocalArea (&component, component.getLocalBounds());
|
||||
|
||||
glBounds = Desktop::getInstance().getDisplays().logicalToPhysical (glBounds);
|
||||
|
||||
|
|
@ -96,9 +108,9 @@ public:
|
|||
glBounds.getX(), glBounds.getY(),
|
||||
(unsigned int) jmax (1, glBounds.getWidth()),
|
||||
(unsigned int) jmax (1, glBounds.getHeight()),
|
||||
0, bestVisual->depth,
|
||||
0, visual->depth,
|
||||
InputOutput,
|
||||
bestVisual->visual,
|
||||
visual->visual,
|
||||
CWBorderPixel | CWColormap | CWEventMask,
|
||||
&swa);
|
||||
|
||||
|
|
@ -135,18 +147,59 @@ public:
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bestVisual != nullptr)
|
||||
X11Symbols::getInstance()->xFree (bestVisual);
|
||||
}
|
||||
|
||||
bool initialiseOnRenderThread (OpenGLContext& c)
|
||||
{
|
||||
XWindowSystemUtilities::ScopedXLock xLock;
|
||||
renderContext = glXCreateContext (display, bestVisual, (GLXContext) contextToShareWith, GL_TRUE);
|
||||
|
||||
const auto components = [&]() -> Optional<Version>
|
||||
{
|
||||
switch (c.versionRequired)
|
||||
{
|
||||
case OpenGLVersion::openGL3_2: return Version { 3, 2 };
|
||||
case OpenGLVersion::openGL4_1: return Version { 4, 1 };
|
||||
case OpenGLVersion::openGL4_3: return Version { 4, 3 };
|
||||
|
||||
case OpenGLVersion::defaultGLVersion: break;
|
||||
}
|
||||
|
||||
return {};
|
||||
}();
|
||||
|
||||
if (components.hasValue())
|
||||
{
|
||||
using GLXCreateContextAttribsARB = GLXContext (*) (Display*, GLXFBConfig, GLXContext, Bool, const int*);
|
||||
|
||||
if (const auto glXCreateContextAttribsARB = (GLXCreateContextAttribsARB) OpenGLHelpers::getExtensionFunction ("glXCreateContextAttribsARB"))
|
||||
{
|
||||
#if JUCE_DEBUG
|
||||
constexpr auto contextFlags = GLX_CONTEXT_DEBUG_BIT_ARB;
|
||||
#else
|
||||
constexpr auto contextFlags = 0;
|
||||
#endif
|
||||
|
||||
const int attribs[]
|
||||
{
|
||||
GLX_CONTEXT_MAJOR_VERSION_ARB, components->major,
|
||||
GLX_CONTEXT_MINOR_VERSION_ARB, components->minor,
|
||||
GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
|
||||
GLX_CONTEXT_FLAGS_ARB, contextFlags,
|
||||
None
|
||||
};
|
||||
|
||||
renderContext = glXCreateContextAttribsARB (display, *bestConfig, (GLXContext) contextToShareWith, GL_TRUE, attribs);
|
||||
}
|
||||
}
|
||||
|
||||
if (renderContext == nullptr)
|
||||
renderContext = glXCreateNewContext (display, *bestConfig, GLX_RGBA_TYPE, (GLXContext) contextToShareWith, GL_TRUE);
|
||||
|
||||
if (renderContext == nullptr)
|
||||
return false;
|
||||
|
||||
c.makeActive();
|
||||
context = &c;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -234,8 +287,8 @@ private:
|
|||
{
|
||||
std::vector<GLint> allAttribs
|
||||
{
|
||||
GLX_RGBA,
|
||||
GLX_DOUBLEBUFFER,
|
||||
GLX_RENDER_TYPE, GLX_RGBA_BIT,
|
||||
GLX_DOUBLEBUFFER, True,
|
||||
GLX_RED_SIZE, format.redBits,
|
||||
GLX_GREEN_SIZE, format.greenBits,
|
||||
GLX_BLUE_SIZE, format.blueBits,
|
||||
|
|
@ -252,9 +305,10 @@ private:
|
|||
|
||||
allAttribs.push_back (None);
|
||||
|
||||
bestVisual = glXChooseVisual (display, X11Symbols::getInstance()->xDefaultScreen (display), allAttribs.data());
|
||||
int nElements = 0;
|
||||
bestConfig = makeXFreePtr (glXChooseFBConfig (display, X11Symbols::getInstance()->xDefaultScreen (display), allAttribs.data(), &nElements));
|
||||
|
||||
return bestVisual != nullptr;
|
||||
return nElements != 0 && bestConfig != nullptr;
|
||||
}
|
||||
|
||||
static constexpr int embeddedWindowEventMask = ExposureMask | StructureNotifyMask;
|
||||
|
|
@ -265,7 +319,7 @@ private:
|
|||
|
||||
int swapFrames = 1;
|
||||
Rectangle<int> bounds;
|
||||
XVisualInfo* bestVisual = nullptr;
|
||||
std::unique_ptr<GLXFBConfig, XFreeDeleter> bestConfig;
|
||||
void* contextToShareWith;
|
||||
|
||||
OpenGLContext* context = nullptr;
|
||||
|
|
|
|||
|
|
@ -82,8 +82,17 @@ public:
|
|||
int numAttribs = 0;
|
||||
|
||||
attribs[numAttribs++] = NSOpenGLPFAOpenGLProfile;
|
||||
attribs[numAttribs++] = version >= openGL3_2 ? NSOpenGLProfileVersion3_2Core
|
||||
: NSOpenGLProfileVersionLegacy;
|
||||
attribs[numAttribs++] = [version]
|
||||
{
|
||||
if (version == openGL3_2)
|
||||
return NSOpenGLProfileVersion3_2Core;
|
||||
|
||||
if (version != defaultGLVersion)
|
||||
if (@available (macOS 10.10, *))
|
||||
return NSOpenGLProfileVersion4_1Core;
|
||||
|
||||
return NSOpenGLProfileVersionLegacy;
|
||||
}();
|
||||
|
||||
attribs[numAttribs++] = NSOpenGLPFADoubleBuffer;
|
||||
attribs[numAttribs++] = NSOpenGLPFAClosestPolicy;
|
||||
|
|
|
|||
|
|
@ -206,13 +206,34 @@ private:
|
|||
|
||||
static HGLRC createRenderContext (OpenGLVersion version, HDC dcIn)
|
||||
{
|
||||
if (version >= openGL3_2 && wglCreateContextAttribsARB != nullptr)
|
||||
const auto components = [&]() -> Optional<Version>
|
||||
{
|
||||
switch (version)
|
||||
{
|
||||
case OpenGLVersion::openGL3_2: return Version { 3, 2 };
|
||||
case OpenGLVersion::openGL4_1: return Version { 4, 1 };
|
||||
case OpenGLVersion::openGL4_3: return Version { 4, 3 };
|
||||
|
||||
case OpenGLVersion::defaultGLVersion: break;
|
||||
}
|
||||
|
||||
return {};
|
||||
}();
|
||||
|
||||
if (components.hasValue() && wglCreateContextAttribsARB != nullptr)
|
||||
{
|
||||
#if JUCE_DEBUG
|
||||
constexpr auto contextFlags = WGL_CONTEXT_DEBUG_BIT_ARB;
|
||||
#else
|
||||
constexpr auto contextFlags = 0;
|
||||
#endif
|
||||
|
||||
const int attribs[] =
|
||||
{
|
||||
WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
|
||||
WGL_CONTEXT_MINOR_VERSION_ARB, 2,
|
||||
WGL_CONTEXT_MAJOR_VERSION_ARB, components->major,
|
||||
WGL_CONTEXT_MINOR_VERSION_ARB, components->minor,
|
||||
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
|
||||
WGL_CONTEXT_FLAGS_ARB, contextFlags,
|
||||
0
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -461,10 +461,8 @@ public:
|
|||
|
||||
void drawComponentBuffer()
|
||||
{
|
||||
#if ! JUCE_ANDROID
|
||||
glEnable (GL_TEXTURE_2D);
|
||||
clearGLError();
|
||||
#endif
|
||||
if (contextRequiresTexture2DEnableDisable())
|
||||
glEnable (GL_TEXTURE_2D);
|
||||
|
||||
#if JUCE_WINDOWS
|
||||
// some stupidly old drivers are missing this function, so try to at least avoid a crash here,
|
||||
|
|
@ -473,7 +471,9 @@ public:
|
|||
jassert (context.extensions.glActiveTexture != nullptr);
|
||||
if (context.extensions.glActiveTexture != nullptr)
|
||||
#endif
|
||||
{
|
||||
context.extensions.glActiveTexture (GL_TEXTURE0);
|
||||
}
|
||||
|
||||
glBindTexture (GL_TEXTURE_2D, cachedImageFrameBuffer.getTextureID());
|
||||
bindVertexArray();
|
||||
|
|
@ -622,6 +622,21 @@ public:
|
|||
bindVertexArray();
|
||||
}
|
||||
|
||||
#if JUCE_DEBUG
|
||||
if (getOpenGLVersion() >= Version { 4, 3 } && glDebugMessageCallback != nullptr)
|
||||
{
|
||||
glEnable (GL_DEBUG_OUTPUT);
|
||||
glDebugMessageCallback ([] (GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar* message, const void*)
|
||||
{
|
||||
// This may reiterate issues that are also flagged by JUCE_CHECK_OPENGL_ERROR.
|
||||
// The advantage of this callback is that it will catch *all* errors, even if we
|
||||
// forget to check manually.
|
||||
DBG ("OpenGL DBG message: " << message);
|
||||
jassertfalse;
|
||||
}, nullptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
const auto currentViewportArea = areaAndScale.get().area;
|
||||
glViewport (0, 0, currentViewportArea.getWidth(), currentViewportArea.getHeight());
|
||||
|
||||
|
|
|
|||
|
|
@ -136,8 +136,10 @@ public:
|
|||
/** OpenGL versions, used by setOpenGLVersionRequired(). */
|
||||
enum OpenGLVersion
|
||||
{
|
||||
defaultGLVersion = 0,
|
||||
openGL3_2
|
||||
defaultGLVersion = 0, ///< Whatever the device decides to give us, normally a compatibility profile
|
||||
openGL3_2, ///< 3.2 Core profile
|
||||
openGL4_1, ///< 4.1 Core profile, the latest supported by macOS at time of writing
|
||||
openGL4_3 ///< 4.3 Core profile, will enable improved debugging support when building in Debug
|
||||
};
|
||||
|
||||
/** Sets a preference for the version of GL that this context should use, if possible.
|
||||
|
|
|
|||
|
|
@ -964,8 +964,10 @@ struct StateHelpers
|
|||
//==============================================================================
|
||||
struct ActiveTextures
|
||||
{
|
||||
ActiveTextures (const OpenGLContext& c) noexcept : context (c)
|
||||
{}
|
||||
explicit ActiveTextures (const OpenGLContext& c) noexcept
|
||||
: context (c)
|
||||
{
|
||||
}
|
||||
|
||||
void clear() noexcept
|
||||
{
|
||||
|
|
@ -979,23 +981,28 @@ struct StateHelpers
|
|||
{
|
||||
quadQueue.flush();
|
||||
|
||||
for (int i = 3; --i >= 0;)
|
||||
for (int i = numTextures; --i >= 0;)
|
||||
{
|
||||
if ((texturesEnabled & (1 << i)) != (textureIndexMask & (1 << i)))
|
||||
{
|
||||
setActiveTexture (i);
|
||||
JUCE_CHECK_OPENGL_ERROR
|
||||
|
||||
#if ! JUCE_ANDROID
|
||||
if ((textureIndexMask & (1 << i)) != 0)
|
||||
glEnable (GL_TEXTURE_2D);
|
||||
else
|
||||
{
|
||||
glDisable (GL_TEXTURE_2D);
|
||||
currentTextureID[i] = 0;
|
||||
}
|
||||
const auto thisTextureEnabled = (textureIndexMask & (1 << i)) != 0;
|
||||
|
||||
clearGLError();
|
||||
if (! thisTextureEnabled)
|
||||
currentTextureID[i] = 0;
|
||||
|
||||
#if ! JUCE_ANDROID
|
||||
if (needsToEnableTexture)
|
||||
{
|
||||
if (thisTextureEnabled)
|
||||
glEnable (GL_TEXTURE_2D);
|
||||
else
|
||||
glDisable (GL_TEXTURE_2D);
|
||||
|
||||
JUCE_CHECK_OPENGL_ERROR
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
@ -1079,6 +1086,7 @@ struct StateHelpers
|
|||
GLuint currentTextureID[numTextures];
|
||||
int texturesEnabled = 0, currentActiveTexture = -1;
|
||||
const OpenGLContext& context;
|
||||
const bool needsToEnableTexture = contextRequiresTexture2DEnableDisable();
|
||||
|
||||
ActiveTextures& operator= (const ActiveTextures&);
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue