|
|
@@ -74,18 +74,7 @@ public: |
|
|
|
CachedImage (OpenGLContext& c, Component& comp,
|
|
|
|
const OpenGLPixelFormat& pixFormat, void* contextToShare)
|
|
|
|
: ThreadPoolJob ("OpenGL Rendering"),
|
|
|
|
context (c), component (comp),
|
|
|
|
scale (1.0),
|
|
|
|
#if JUCE_OPENGL3
|
|
|
|
vertexArrayObject (0),
|
|
|
|
#endif
|
|
|
|
#if JUCE_OPENGL_ES
|
|
|
|
shadersAvailable (true),
|
|
|
|
#else
|
|
|
|
shadersAvailable (false),
|
|
|
|
#endif
|
|
|
|
hasInitialised (false),
|
|
|
|
needsUpdate (1), lastMMLockReleaseTime (0)
|
|
|
|
context (c), component (comp)
|
|
|
|
{
|
|
|
|
nativeContext = new NativeContext (component, pixFormat, contextToShare,
|
|
|
|
c.useMultisampling, c.versionRequired);
|
|
|
@@ -180,8 +169,8 @@ public: |
|
|
|
//==============================================================================
|
|
|
|
bool ensureFrameBufferSize()
|
|
|
|
{
|
|
|
|
const int fbW = cachedImageFrameBuffer.getWidth();
|
|
|
|
const int fbH = cachedImageFrameBuffer.getHeight();
|
|
|
|
auto fbW = cachedImageFrameBuffer.getWidth();
|
|
|
|
auto fbH = cachedImageFrameBuffer.getHeight();
|
|
|
|
|
|
|
|
if (fbW != viewportArea.getWidth() || fbH != viewportArea.getHeight() || ! cachedImageFrameBuffer.isValid())
|
|
|
|
{
|
|
|
@@ -200,9 +189,9 @@ public: |
|
|
|
glClearColor (0, 0, 0, 0);
|
|
|
|
glEnable (GL_SCISSOR_TEST);
|
|
|
|
|
|
|
|
const GLuint previousFrameBufferTarget = OpenGLFrameBuffer::getCurrentFrameBufferTarget();
|
|
|
|
auto previousFrameBufferTarget = OpenGLFrameBuffer::getCurrentFrameBufferTarget();
|
|
|
|
cachedImageFrameBuffer.makeCurrentRenderingTarget();
|
|
|
|
const int imageH = cachedImageFrameBuffer.getHeight();
|
|
|
|
auto imageH = cachedImageFrameBuffer.getHeight();
|
|
|
|
|
|
|
|
for (auto& r : list)
|
|
|
|
{
|
|
|
@@ -280,16 +269,16 @@ public: |
|
|
|
|
|
|
|
void updateViewportSize (bool canTriggerUpdate)
|
|
|
|
{
|
|
|
|
if (ComponentPeer* peer = component.getPeer())
|
|
|
|
if (auto* peer = component.getPeer())
|
|
|
|
{
|
|
|
|
lastScreenBounds = component.getTopLevelComponent()->getScreenBounds();
|
|
|
|
|
|
|
|
const double newScale = Desktop::getInstance().getDisplays()
|
|
|
|
.getDisplayContaining (lastScreenBounds.getCentre()).scale;
|
|
|
|
auto newScale = Desktop::getInstance().getDisplays()
|
|
|
|
.getDisplayContaining (lastScreenBounds.getCentre()).scale;
|
|
|
|
|
|
|
|
Rectangle<int> newArea (peer->getComponent().getLocalArea (&component, component.getLocalBounds())
|
|
|
|
.withZeroOrigin()
|
|
|
|
* newScale);
|
|
|
|
auto newArea = peer->getComponent().getLocalArea (&component, component.getLocalBounds())
|
|
|
|
.withZeroOrigin()
|
|
|
|
* newScale;
|
|
|
|
|
|
|
|
if (scale != newScale || viewportArea != newArea)
|
|
|
|
{
|
|
|
@@ -312,7 +301,7 @@ public: |
|
|
|
|
|
|
|
void checkViewportBounds()
|
|
|
|
{
|
|
|
|
const Rectangle<int> screenBounds (component.getTopLevelComponent()->getScreenBounds());
|
|
|
|
auto screenBounds = component.getTopLevelComponent()->getScreenBounds();
|
|
|
|
|
|
|
|
if (lastScreenBounds != screenBounds)
|
|
|
|
updateViewportSize (true);
|
|
|
@@ -524,7 +513,7 @@ public: |
|
|
|
}
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
struct MessageLockWorker : MessageManagerLock::BailOutChecker
|
|
|
|
struct MessageLockWorker : public MessageManagerLock::BailOutChecker
|
|
|
|
{
|
|
|
|
MessageLockWorker (CachedImage& cachedImageRequestingLock)
|
|
|
|
: owner (cachedImageRequestingLock)
|
|
|
@@ -534,11 +523,11 @@ public: |
|
|
|
bool shouldAbortAcquiringLock() override { return owner.doWorkWhileWaitingForLock (false); }
|
|
|
|
|
|
|
|
CachedImage& owner;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE(MessageLockWorker)
|
|
|
|
JUCE_DECLARE_NON_COPYABLE (MessageLockWorker)
|
|
|
|
};
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
struct BlockingWorker : OpenGLContext::AsyncWorker
|
|
|
|
struct BlockingWorker : public OpenGLContext::AsyncWorker
|
|
|
|
{
|
|
|
|
BlockingWorker (OpenGLContext::AsyncWorker::Ptr && workerToUse)
|
|
|
|
: originalWorker (static_cast<OpenGLContext::AsyncWorker::Ptr&&> (workerToUse))
|
|
|
@@ -552,7 +541,7 @@ public: |
|
|
|
finishedSignal.signal();
|
|
|
|
}
|
|
|
|
|
|
|
|
void block() { finishedSignal.wait(); }
|
|
|
|
void block() noexcept { finishedSignal.wait(); }
|
|
|
|
|
|
|
|
OpenGLContext::AsyncWorker::Ptr originalWorker;
|
|
|
|
WaitableEvent finishedSignal;
|
|
|
@@ -599,7 +588,9 @@ public: |
|
|
|
blocker->block();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
jassertfalse; // you called execute AFTER you detached your openglcontext
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
@@ -610,7 +601,7 @@ public: |
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
// used to push no work on to the gl thread to easily block
|
|
|
|
struct DoNothingWorker : OpenGLContext::AsyncWorker
|
|
|
|
struct DoNothingWorker : public OpenGLContext::AsyncWorker
|
|
|
|
{
|
|
|
|
DoNothingWorker() {}
|
|
|
|
void operator() (OpenGLContext&) override {}
|
|
|
@@ -625,18 +616,23 @@ public: |
|
|
|
OpenGLFrameBuffer cachedImageFrameBuffer;
|
|
|
|
RectangleList<int> validArea;
|
|
|
|
Rectangle<int> viewportArea, lastScreenBounds;
|
|
|
|
double scale;
|
|
|
|
double scale = 1.0;
|
|
|
|
#if JUCE_OPENGL3
|
|
|
|
GLuint vertexArrayObject;
|
|
|
|
GLuint vertexArrayObject = 0;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
StringArray associatedObjectNames;
|
|
|
|
ReferenceCountedArray<ReferenceCountedObject> associatedObjects;
|
|
|
|
|
|
|
|
WaitableEvent canPaintNowFlag, finishedPaintingFlag, repaintEvent;
|
|
|
|
bool shadersAvailable, hasInitialised;
|
|
|
|
Atomic<int> needsUpdate, destroying;
|
|
|
|
uint32 lastMMLockReleaseTime;
|
|
|
|
#if JUCE_OPENGL_ES
|
|
|
|
bool shadersAvailable = true;
|
|
|
|
#else
|
|
|
|
bool shadersAvailable = false;
|
|
|
|
#endif
|
|
|
|
bool hasInitialised = false;
|
|
|
|
Atomic<int> needsUpdate { 1 }, destroying;
|
|
|
|
uint32 lastMMLockReleaseTime = 0;
|
|
|
|
|
|
|
|
ScopedPointer<ThreadPool> renderThread;
|
|
|
|
ReferenceCountedArray<OpenGLContext::AsyncWorker, CriticalSection> workQueue;
|
|
|
@@ -667,17 +663,15 @@ public: |
|
|
|
|
|
|
|
void detach()
|
|
|
|
{
|
|
|
|
Component& comp = *getComponent();
|
|
|
|
|
|
|
|
auto& comp = *getComponent();
|
|
|
|
stop();
|
|
|
|
|
|
|
|
comp.setCachedComponentImage (nullptr);
|
|
|
|
context.nativeContext = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void componentMovedOrResized (bool /*wasMoved*/, bool /*wasResized*/) override
|
|
|
|
{
|
|
|
|
Component& comp = *getComponent();
|
|
|
|
auto& comp = *getComponent();
|
|
|
|
|
|
|
|
if (isAttached (comp) != canBeAttached (comp))
|
|
|
|
componentVisibilityChanged();
|
|
|
@@ -685,10 +679,10 @@ public: |
|
|
|
if (comp.getWidth() > 0 && comp.getHeight() > 0
|
|
|
|
&& context.nativeContext != nullptr)
|
|
|
|
{
|
|
|
|
if (CachedImage* const c = CachedImage::get (comp))
|
|
|
|
if (auto* c = CachedImage::get (comp))
|
|
|
|
c->handleResize();
|
|
|
|
|
|
|
|
if (ComponentPeer* peer = comp.getTopLevelComponent()->getPeer())
|
|
|
|
if (auto* peer = comp.getTopLevelComponent()->getPeer())
|
|
|
|
context.nativeContext->updateWindowPosition (peer->getAreaCoveredBy (comp));
|
|
|
|
}
|
|
|
|
}
|
|
|
@@ -701,7 +695,7 @@ public: |
|
|
|
|
|
|
|
void componentVisibilityChanged() override
|
|
|
|
{
|
|
|
|
Component& comp = *getComponent();
|
|
|
|
auto& comp = *getComponent();
|
|
|
|
|
|
|
|
if (canBeAttached (comp))
|
|
|
|
{
|
|
|
@@ -730,7 +724,7 @@ public: |
|
|
|
|
|
|
|
void update()
|
|
|
|
{
|
|
|
|
Component& comp = *getComponent();
|
|
|
|
auto& comp = *getComponent();
|
|
|
|
|
|
|
|
if (canBeAttached (comp))
|
|
|
|
start();
|
|
|
@@ -751,7 +745,7 @@ private: |
|
|
|
if (! c.isVisible())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (Component* p = c.getParentComponent())
|
|
|
|
if (auto* p = c.getParentComponent())
|
|
|
|
return isShowingOrMinimised (*p);
|
|
|
|
|
|
|
|
return c.getPeer() != nullptr;
|
|
|
@@ -764,10 +758,10 @@ private: |
|
|
|
|
|
|
|
void attach()
|
|
|
|
{
|
|
|
|
Component& comp = *getComponent();
|
|
|
|
CachedImage* const newCachedImage = new CachedImage (context, comp,
|
|
|
|
context.openGLPixelFormat,
|
|
|
|
context.contextToShareWith);
|
|
|
|
auto& comp = *getComponent();
|
|
|
|
auto* newCachedImage = new CachedImage (context, comp,
|
|
|
|
context.openGLPixelFormat,
|
|
|
|
context.contextToShareWith);
|
|
|
|
comp.setCachedComponentImage (newCachedImage);
|
|
|
|
|
|
|
|
start();
|
|
|
@@ -777,21 +771,21 @@ private: |
|
|
|
{
|
|
|
|
stopTimer();
|
|
|
|
|
|
|
|
Component& comp = *getComponent();
|
|
|
|
auto& comp = *getComponent();
|
|
|
|
|
|
|
|
#if JUCE_MAC
|
|
|
|
[[(NSView*) comp.getWindowHandle() window] disableScreenUpdatesUntilFlush];
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (CachedImage* const oldCachedImage = CachedImage::get (comp))
|
|
|
|
if (auto* oldCachedImage = CachedImage::get (comp))
|
|
|
|
oldCachedImage->stop(); // (must stop this before detaching it from the component)
|
|
|
|
}
|
|
|
|
|
|
|
|
void start()
|
|
|
|
{
|
|
|
|
Component& comp = *getComponent();
|
|
|
|
auto& comp = *getComponent();
|
|
|
|
|
|
|
|
if (CachedImage* const cachedImage = CachedImage::get (comp))
|
|
|
|
if (auto* cachedImage = CachedImage::get (comp))
|
|
|
|
{
|
|
|
|
cachedImage->start(); // (must wait until this is attached before starting its thread)
|
|
|
|
cachedImage->updateViewportSize (true);
|
|
|
@@ -802,21 +796,13 @@ private: |
|
|
|
|
|
|
|
void timerCallback() override
|
|
|
|
{
|
|
|
|
if (CachedImage* const cachedImage = CachedImage::get (*getComponent()))
|
|
|
|
if (auto* cachedImage = CachedImage::get (*getComponent()))
|
|
|
|
cachedImage->checkViewportBounds();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
OpenGLContext::OpenGLContext()
|
|
|
|
: nativeContext (nullptr), renderer (nullptr),
|
|
|
|
currentRenderScale (1.0), contextToShareWith (nullptr),
|
|
|
|
versionRequired (OpenGLContext::defaultGLVersion),
|
|
|
|
imageCacheMaxSize (8 * 1024 * 1024),
|
|
|
|
renderComponents (true),
|
|
|
|
useMultisampling (false),
|
|
|
|
continuousRepaint (false),
|
|
|
|
overrideCanAttach (false)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
@@ -894,7 +880,7 @@ void OpenGLContext::attachTo (Component& component) |
|
|
|
|
|
|
|
void OpenGLContext::detach()
|
|
|
|
{
|
|
|
|
if (Attachment* a = attachment)
|
|
|
|
if (auto* a = attachment.get())
|
|
|
|
{
|
|
|
|
a->detach(); // must detach before nulling our pointer
|
|
|
|
attachment = nullptr;
|
|
|
@@ -915,7 +901,7 @@ Component* OpenGLContext::getTargetComponent() const noexcept |
|
|
|
|
|
|
|
OpenGLContext* OpenGLContext::getContextAttachedTo (Component& c) noexcept
|
|
|
|
{
|
|
|
|
if (CachedImage* const ci = CachedImage::get (c))
|
|
|
|
if (auto* ci = CachedImage::get (c))
|
|
|
|
return &(ci->context);
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
@@ -930,7 +916,7 @@ OpenGLContext* OpenGLContext::getCurrentContext() |
|
|
|
|
|
|
|
bool OpenGLContext::makeActive() const noexcept
|
|
|
|
{
|
|
|
|
OpenGLContext*& current = currentThreadActiveContext.get();
|
|
|
|
auto& current = currentThreadActiveContext.get();
|
|
|
|
|
|
|
|
if (nativeContext != nullptr && nativeContext->makeActive())
|
|
|
|
{
|
|
|
@@ -955,7 +941,7 @@ void OpenGLContext::deactivateCurrentContext() |
|
|
|
|
|
|
|
void OpenGLContext::triggerRepaint()
|
|
|
|
{
|
|
|
|
if (CachedImage* const cachedImage = getCachedImage())
|
|
|
|
if (auto* cachedImage = getCachedImage())
|
|
|
|
cachedImage->triggerRepaint();
|
|
|
|
}
|
|
|
|
|
|
|
@@ -987,7 +973,7 @@ void* OpenGLContext::getRawContext() const noexcept |
|
|
|
|
|
|
|
OpenGLContext::CachedImage* OpenGLContext::getCachedImage() const noexcept
|
|
|
|
{
|
|
|
|
if (Component* const comp = getTargetComponent())
|
|
|
|
if (auto* comp = getTargetComponent())
|
|
|
|
return CachedImage::get (*comp);
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
@@ -995,7 +981,7 @@ OpenGLContext::CachedImage* OpenGLContext::getCachedImage() const noexcept |
|
|
|
|
|
|
|
bool OpenGLContext::areShadersAvailable() const
|
|
|
|
{
|
|
|
|
CachedImage* const c = getCachedImage();
|
|
|
|
auto* c = getCachedImage();
|
|
|
|
return c != nullptr && c->shadersAvailable;
|
|
|
|
}
|
|
|
|
|
|
|
@@ -1003,7 +989,7 @@ ReferenceCountedObject* OpenGLContext::getAssociatedObject (const char* name) co |
|
|
|
{
|
|
|
|
jassert (name != nullptr);
|
|
|
|
|
|
|
|
CachedImage* const c = getCachedImage();
|
|
|
|
auto* c = getCachedImage();
|
|
|
|
|
|
|
|
// This method must only be called from an openGL rendering callback.
|
|
|
|
jassert (c != nullptr && nativeContext != nullptr);
|
|
|
@@ -1017,7 +1003,7 @@ void OpenGLContext::setAssociatedObject (const char* name, ReferenceCountedObjec |
|
|
|
{
|
|
|
|
jassert (name != nullptr);
|
|
|
|
|
|
|
|
if (CachedImage* const c = getCachedImage())
|
|
|
|
if (auto* c = getCachedImage())
|
|
|
|
{
|
|
|
|
// This method must only be called from an openGL rendering callback.
|
|
|
|
jassert (nativeContext != nullptr);
|
|
|
@@ -1050,7 +1036,7 @@ size_t OpenGLContext::getImageCacheSize() const noexcept { return ima |
|
|
|
|
|
|
|
void OpenGLContext::execute (OpenGLContext::AsyncWorker::Ptr workerToUse, bool shouldBlock)
|
|
|
|
{
|
|
|
|
if (CachedImage* const c = getCachedImage())
|
|
|
|
if (auto* c = getCachedImage())
|
|
|
|
c->execute (static_cast<OpenGLContext::AsyncWorker::Ptr&&> (workerToUse), shouldBlock);
|
|
|
|
else
|
|
|
|
jassertfalse; // You must have attached the context to a component
|
|
|
@@ -1062,7 +1048,7 @@ void OpenGLContext::overrideCanBeAttached (bool newCanAttach) |
|
|
|
{
|
|
|
|
overrideCanAttach = newCanAttach;
|
|
|
|
|
|
|
|
if (Attachment* a = attachment)
|
|
|
|
if (auto* a = attachment.get())
|
|
|
|
a->update();
|
|
|
|
}
|
|
|
|
}
|
|
|
@@ -1185,13 +1171,13 @@ void OpenGLContext::copyTexture (const Rectangle<int>& targetClipArea, |
|
|
|
Params params;
|
|
|
|
};
|
|
|
|
|
|
|
|
const GLshort left = (GLshort) targetClipArea.getX();
|
|
|
|
const GLshort top = (GLshort) targetClipArea.getY();
|
|
|
|
const GLshort right = (GLshort) targetClipArea.getRight();
|
|
|
|
const GLshort bottom = (GLshort) targetClipArea.getBottom();
|
|
|
|
auto left = (GLshort) targetClipArea.getX();
|
|
|
|
auto top = (GLshort) targetClipArea.getY();
|
|
|
|
auto right = (GLshort) targetClipArea.getRight();
|
|
|
|
auto bottom = (GLshort) targetClipArea.getBottom();
|
|
|
|
const GLshort vertices[] = { left, bottom, right, bottom, left, top, right, top };
|
|
|
|
|
|
|
|
const OverlayShaderProgram& program = OverlayShaderProgram::select (*this);
|
|
|
|
auto& program = OverlayShaderProgram::select (*this);
|
|
|
|
program.params.set ((float) contextWidth, (float) contextHeight, anchorPosAndTextureSize.toFloat(), flippedVertically);
|
|
|
|
|
|
|
|
GLuint vertexBuffer = 0;
|
|
|
@@ -1199,7 +1185,7 @@ void OpenGLContext::copyTexture (const Rectangle<int>& targetClipArea, |
|
|
|
extensions.glBindBuffer (GL_ARRAY_BUFFER, vertexBuffer);
|
|
|
|
extensions.glBufferData (GL_ARRAY_BUFFER, sizeof (vertices), vertices, GL_STATIC_DRAW);
|
|
|
|
|
|
|
|
const GLuint index = (GLuint) program.params.positionAttribute.attributeID;
|
|
|
|
auto index = (GLuint) program.params.positionAttribute.attributeID;
|
|
|
|
extensions.glVertexAttribPointer (index, 2, GL_SHORT, GL_FALSE, 4, 0);
|
|
|
|
extensions.glEnableVertexAttribArray (index);
|
|
|
|
JUCE_CHECK_OPENGL_ERROR
|
|
|
|