From a997490f171b47352f241600961ad23bf6ef4f96 Mon Sep 17 00:00:00 2001 From: jules Date: Fri, 23 Dec 2011 10:33:05 +0000 Subject: [PATCH] Updated the OpenGLComponent so that it can render sub-components when using a background thread, and changed the demo to use this mode (which is faster). --- extras/JuceDemo/Source/MainDemoWindow.cpp | 1 + .../VST/juce_VST_Wrapper.cpp | 2 +- .../messages/juce_MessageManager.cpp | 80 ++-- .../messages/juce_MessageManager.h | 4 +- .../windows/juce_ComponentPeer.cpp | 4 +- .../windows/juce_ComponentPeer.h | 2 +- .../native/juce_ios_OpenGLComponent.mm | 2 + .../native/juce_linux_OpenGLComponent.cpp | 2 + .../native/juce_win32_OpenGLComponent.cpp | 2 + .../opengl/juce_OpenGLComponent.cpp | 374 +++++++++--------- .../juce_opengl/opengl/juce_OpenGLComponent.h | 15 +- .../native/juce_win32_DirectShowComponent.cpp | 5 +- 12 files changed, 251 insertions(+), 242 deletions(-) diff --git a/extras/JuceDemo/Source/MainDemoWindow.cpp b/extras/JuceDemo/Source/MainDemoWindow.cpp index d7f106f46d..0073be314a 100644 --- a/extras/JuceDemo/Source/MainDemoWindow.cpp +++ b/extras/JuceDemo/Source/MainDemoWindow.cpp @@ -519,6 +519,7 @@ private: { public: DemoOpenGLComp (Component* contentComp) + : OpenGLComponent (useBackgroundThread | allowSubComponents) { addAndMakeVisible (contentComp); } diff --git a/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp b/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp index 4d298d8217..56bf46c7f6 100644 --- a/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp +++ b/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp @@ -1062,7 +1062,7 @@ public: Window editorWnd = (Window) editorComp->getWindowHandle(); XReparentWindow (display, editorWnd, hostWindow, 0, 0); #else - hostWindow = attachComponentToWindowRef (editorComp, (WindowRef) ptr); + hostWindow = attachComponentToWindowRef (editorComp, ptr); #endif editorComp->setVisible (true); diff --git a/modules/juce_events/messages/juce_MessageManager.cpp b/modules/juce_events/messages/juce_MessageManager.cpp index bdb8c925fe..32b8caa911 100644 --- a/modules/juce_events/messages/juce_MessageManager.cpp +++ b/modules/juce_events/messages/juce_MessageManager.cpp @@ -241,64 +241,58 @@ private: //============================================================================== MessageManagerLock::MessageManagerLock (Thread* const threadToCheck) - : locked (false) + : blockingMessage(), locked (attemptLock (threadToCheck, nullptr)) { - init (threadToCheck, nullptr); } MessageManagerLock::MessageManagerLock (ThreadPoolJob* const jobToCheckForExitSignal) - : locked (false) + : blockingMessage(), locked (attemptLock (nullptr, jobToCheckForExitSignal)) { - init (nullptr, jobToCheckForExitSignal); } -void MessageManagerLock::init (Thread* const threadToCheck, ThreadPoolJob* const job) +bool MessageManagerLock::attemptLock (Thread* const threadToCheck, ThreadPoolJob* const job) { - if (MessageManager::instance != nullptr) + if (MessageManager::instance == nullptr) + return false; + + if (MessageManager::instance->currentThreadHasLockedMessageManager()) + return true; + + if (threadToCheck == nullptr && job == nullptr) { - if (MessageManager::instance->currentThreadHasLockedMessageManager()) - { - locked = true; // either we're on the message thread, or this is a re-entrant call. - } - else + MessageManager::instance->lockingLock.enter(); + } + else + { + while (! MessageManager::instance->lockingLock.tryEnter()) { - if (threadToCheck == nullptr && job == nullptr) - { - MessageManager::instance->lockingLock.enter(); - } - else - { - while (! MessageManager::instance->lockingLock.tryEnter()) - { - if ((threadToCheck != nullptr && threadToCheck->threadShouldExit()) - || (job != nullptr && job->shouldExit())) - return; - - Thread::sleep (1); - } - } + if ((threadToCheck != nullptr && threadToCheck->threadShouldExit()) + || (job != nullptr && job->shouldExit())) + return false; - blockingMessage = new BlockingMessage(); - blockingMessage->post(); - - while (! blockingMessage->lockedEvent.wait (20)) - { - if ((threadToCheck != nullptr && threadToCheck->threadShouldExit()) - || (job != nullptr && job->shouldExit())) - { - blockingMessage->releaseEvent.signal(); - blockingMessage = nullptr; - MessageManager::instance->lockingLock.exit(); - return; - } - } + Thread::sleep (1); + } + } - jassert (MessageManager::instance->threadWithLock == 0); + blockingMessage = new BlockingMessage(); + blockingMessage->post(); - MessageManager::instance->threadWithLock = Thread::getCurrentThreadId(); - locked = true; + while (! blockingMessage->lockedEvent.wait (20)) + { + if ((threadToCheck != nullptr && threadToCheck->threadShouldExit()) + || (job != nullptr && job->shouldExit())) + { + blockingMessage->releaseEvent.signal(); + blockingMessage = nullptr; + MessageManager::instance->lockingLock.exit(); + return false; } } + + jassert (MessageManager::instance->threadWithLock == 0); + + MessageManager::instance->threadWithLock = Thread::getCurrentThreadId(); + return true; } MessageManagerLock::~MessageManagerLock() noexcept diff --git a/modules/juce_events/messages/juce_MessageManager.h b/modules/juce_events/messages/juce_MessageManager.h index 075f6ef95d..6a0342dd96 100644 --- a/modules/juce_events/messages/juce_MessageManager.h +++ b/modules/juce_events/messages/juce_MessageManager.h @@ -273,7 +273,7 @@ public: @endcode */ - MessageManagerLock (Thread* threadToCheckForExitSignal = 0); + MessageManagerLock (Thread* threadToCheckForExitSignal = nullptr); //============================================================================== /** This has the same behaviour as the other constructor, but takes a ThreadPoolJob @@ -304,7 +304,7 @@ private: ReferenceCountedObjectPtr blockingMessage; bool locked; - void init (Thread* thread, ThreadPoolJob* job); + bool attemptLock (Thread*, ThreadPoolJob*); JUCE_DECLARE_NON_COPYABLE (MessageManagerLock); }; diff --git a/modules/juce_gui_basics/windows/juce_ComponentPeer.cpp b/modules/juce_gui_basics/windows/juce_ComponentPeer.cpp index 0acc702404..4afa12ed60 100644 --- a/modules/juce_gui_basics/windows/juce_ComponentPeer.cpp +++ b/modules/juce_gui_basics/windows/juce_ComponentPeer.cpp @@ -549,9 +549,9 @@ void ComponentPeer::clearMaskedRegion() maskedRegion.clear(); } -void ComponentPeer::addMaskedRegion (int x, int y, int w, int h) +void ComponentPeer::addMaskedRegion (const Rectangle& area) { - maskedRegion.add (x, y, w, h); + maskedRegion.add (area); } //============================================================================== diff --git a/modules/juce_gui_basics/windows/juce_ComponentPeer.h b/modules/juce_gui_basics/windows/juce_ComponentPeer.h index 0e9b0db796..351134d773 100644 --- a/modules/juce_gui_basics/windows/juce_ComponentPeer.h +++ b/modules/juce_gui_basics/windows/juce_ComponentPeer.h @@ -334,7 +334,7 @@ public: The masked region is cleared each time before a paint happens, so a component will have to make sure it calls this every time it's painted. */ - void addMaskedRegion (int x, int y, int w, int h); + void addMaskedRegion (const Rectangle& area); //============================================================================== /** Returns the number of currently-active peers. diff --git a/modules/juce_opengl/native/juce_ios_OpenGLComponent.mm b/modules/juce_opengl/native/juce_ios_OpenGLComponent.mm index c4ba375703..859114cbc9 100644 --- a/modules/juce_opengl/native/juce_ios_OpenGLComponent.mm +++ b/modules/juce_opengl/native/juce_ios_OpenGLComponent.mm @@ -230,6 +230,8 @@ OpenGLContext* OpenGLComponent::createContext() void OpenGLComponent::updateEmbeddedPosition (const Rectangle& bounds) { + const ScopedLock sl (contextLock); + if (context != nullptr) static_cast (context.get())->updateWindowPosition (bounds); } diff --git a/modules/juce_opengl/native/juce_linux_OpenGLComponent.cpp b/modules/juce_opengl/native/juce_linux_OpenGLComponent.cpp index 8be9ed127a..ee369bd472 100644 --- a/modules/juce_opengl/native/juce_linux_OpenGLComponent.cpp +++ b/modules/juce_opengl/native/juce_linux_OpenGLComponent.cpp @@ -194,6 +194,8 @@ OpenGLContext* OpenGLComponent::createContext() void OpenGLComponent::updateEmbeddedPosition (const Rectangle& bounds) { + const ScopedLock sl (contextLock); + if (context != nullptr) { Window embeddedWindow = static_cast (context.get())->embeddedWindow; diff --git a/modules/juce_opengl/native/juce_win32_OpenGLComponent.cpp b/modules/juce_opengl/native/juce_win32_OpenGLComponent.cpp index 43440d58a6..b7948de617 100644 --- a/modules/juce_opengl/native/juce_win32_OpenGLComponent.cpp +++ b/modules/juce_opengl/native/juce_win32_OpenGLComponent.cpp @@ -282,6 +282,8 @@ void* OpenGLComponent::getNativeWindowHandle() const void OpenGLComponent::updateEmbeddedPosition (const Rectangle& bounds) { + const ScopedLock sl (contextLock); + if (context != nullptr) { ComponentPeer* peer = static_cast (context.get())->nativeWindow; diff --git a/modules/juce_opengl/opengl/juce_OpenGLComponent.cpp b/modules/juce_opengl/opengl/juce_OpenGLComponent.cpp index 8dbdd3d94b..974f56a87d 100644 --- a/modules/juce_opengl/opengl/juce_OpenGLComponent.cpp +++ b/modules/juce_opengl/opengl/juce_OpenGLComponent.cpp @@ -114,105 +114,6 @@ OpenGLContext* OpenGLContext::getCurrentContext() return nullptr; } -//============================================================================== -class OpenGLComponent::OpenGLComponentWatcher : public ComponentMovementWatcher -{ -public: - OpenGLComponentWatcher (OpenGLComponent& owner_) - : ComponentMovementWatcher (&owner_), - owner (owner_) - { - } - - void componentMovedOrResized (bool /*wasMoved*/, bool /*wasResized*/) - { - owner.updateContextPosition(); - } - - void componentPeerChanged() - { - owner.recreateContextAsync(); - } - - void componentVisibilityChanged() - { - if (! owner.isShowing()) - owner.stopBackgroundThread(); - } - -private: - OpenGLComponent& owner; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenGLComponentWatcher); -}; - -//============================================================================== -class OpenGLComponent::OpenGLComponentRenderThread : public Thread -{ -public: - OpenGLComponentRenderThread (OpenGLComponent& owner_) - : Thread ("OpenGL Render"), - owner (owner_) - { - } - - void run() - { - #if JUCE_LINUX - { - MessageManagerLock mml (this); - - if (! mml.lockWasGained()) - return; - - owner.updateContext(); - owner.updateContextPosition(); - } - #endif - - while (! threadShouldExit()) - { - const uint32 startOfRendering = Time::getMillisecondCounter(); - - if (! owner.renderAndSwapBuffers()) - break; - - const int elapsed = (int) (Time::getMillisecondCounter() - startOfRendering); - Thread::sleep (jmax (1, 20 - elapsed)); - } - - #if JUCE_LINUX - owner.deleteContext(); - #endif - } - -private: - OpenGLComponent& owner; - - JUCE_DECLARE_NON_COPYABLE (OpenGLComponentRenderThread); -}; - -void OpenGLComponent::startRenderThread() -{ - if (renderThread == nullptr) - renderThread = new OpenGLComponentRenderThread (*this); - - renderThread->startThread (6); -} - -void OpenGLComponent::stopRenderThread() -{ - if (renderThread != nullptr) - { - renderThread->stopThread (5000); - renderThread = nullptr; - } - - #if ! JUCE_LINUX - deleteContext(); - #endif -} - //============================================================================== class OpenGLComponent::OpenGLCachedComponentImage : public CachedComponentImage, public Timer // N.B. using a Timer rather than an AsyncUpdater @@ -229,10 +130,7 @@ public: ComponentPeer* const peer = owner.getPeer(); if (peer != nullptr) - { - const Point topLeft (owner.getScreenPosition() - peer->getScreenPosition()); - peer->addMaskedRegion (topLeft.x, topLeft.y, owner.getWidth(), owner.getHeight()); - } + peer->addMaskedRegion (owner.getScreenBounds() - peer->getScreenPosition()); if (owner.isUsingDedicatedThread()) { @@ -279,110 +177,156 @@ public: { stopTimer(); - if (! owner.makeCurrentRenderingTarget()) - return; + owner.performRender(); + owner.releaseAsRenderingTarget(); + } + + void triggerRepaint() + { + owner.needToRepaint = true; - const Rectangle bounds (owner.getLocalBounds()); + if (! owner.isUsingDedicatedThread()) + startTimer (1000 / 70); + } + OpenGLFrameBuffer& getFrameBuffer (int width, int height) + { const int fbW = frameBuffer.getWidth(); const int fbH = frameBuffer.getHeight(); - if (fbW < bounds.getWidth() - || fbH < bounds.getHeight() - || fbW > bounds.getWidth() + 128 - || fbH > bounds.getHeight() + 128 + if (fbW < width + || fbH < height + || fbW > width + 128 + || fbH > height + 128 || ! frameBuffer.isValid()) { - frameBuffer.initialise (bounds.getWidth(), bounds.getHeight()); + frameBuffer.initialise (width, height); validArea.clear(); } - owner.renderOpenGL(); + return frameBuffer; + } - if ((owner.flags & allowSubComponents) != 0) - { - { - RectangleList invalid (bounds); - invalid.subtract (validArea); - validArea = bounds; + RectangleList validArea; - if (! invalid.isEmpty()) - { - OpenGLGraphicsContext g (frameBuffer); - g.clipToRectangleList (invalid); +private: + OpenGLComponent& owner; + OpenGLFrameBuffer frameBuffer; - g.setFill (Colours::transparentBlack); - g.fillRect (bounds, true); - g.setFill (Colours::black); + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenGLCachedComponentImage); +}; - paintOwner (g); - } - } +//============================================================================== +class OpenGLComponent::OpenGLComponentWatcher : public ComponentMovementWatcher +{ +public: + OpenGLComponentWatcher (OpenGLComponent& owner_) + : ComponentMovementWatcher (&owner_), + owner (owner_) + { + } - owner.makeCurrentRenderingTarget(); - OpenGLHelpers::prepareFor2D (bounds.getWidth(), bounds.getHeight()); - glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - glEnable (GL_BLEND); - glColor4f (1.0f, 1.0f, 1.0f, owner.getAlpha()); - frameBuffer.drawAt (0, (float) (bounds.getHeight() - frameBuffer.getHeight())); - } + void componentMovedOrResized (bool /*wasMoved*/, bool /*wasResized*/) + { + owner.updateContextPosition(); + } - owner.swapBuffers(); - owner.releaseAsRenderingTarget(); + void componentPeerChanged() + { + owner.recreateContextAsync(); } - void triggerRepaint() + void componentVisibilityChanged() { - if (! owner.isUsingDedicatedThread()) - startTimer (1000 / 70); + if (! owner.isShowing()) + owner.stopBackgroundThread(); } private: - void paintOwner (OpenGLGraphicsContext& glRenderer) + OpenGLComponent& owner; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenGLComponentWatcher); +}; + +//============================================================================== +class OpenGLComponent::OpenGLComponentRenderThread : public Thread +{ +public: + OpenGLComponentRenderThread (OpenGLComponent& owner_) + : Thread ("OpenGL Render"), + owner (owner_) { - Graphics g (&glRenderer); + } - #if JUCE_ENABLE_REPAINT_DEBUGGING - g.saveState(); + void run() + { + #if JUCE_LINUX + { + MessageManagerLock mml (this); + + if (! mml.lockWasGained()) + return; + + owner.updateContext(); + owner.updateContextPosition(); + } #endif - JUCE_TRY + while (! threadShouldExit()) { - owner.paintEntireComponent (g, false); + const uint32 startOfRendering = Time::getMillisecondCounter(); + + if (! owner.performRender()) + break; + + const int elapsed = (int) (Time::getMillisecondCounter() - startOfRendering); + Thread::sleep (jmax (1, (1000 / 60) - elapsed)); } - JUCE_CATCH_EXCEPTION - - #if JUCE_ENABLE_REPAINT_DEBUGGING - // enabling this code will fill all areas that get repainted with a colour overlay, to show - // clearly when things are being repainted. - g.restoreState(); - - static Random rng; - g.fillAll (Colour ((uint8) rng.nextInt (255), - (uint8) rng.nextInt (255), - (uint8) rng.nextInt (255), - (uint8) 0x50)); + + #if JUCE_LINUX + owner.deleteContext(); #endif } +private: OpenGLComponent& owner; - OpenGLFrameBuffer frameBuffer; - RectangleList validArea; - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenGLCachedComponentImage); + JUCE_DECLARE_NON_COPYABLE (OpenGLComponentRenderThread); }; +void OpenGLComponent::startRenderThread() +{ + if (renderThread == nullptr) + renderThread = new OpenGLComponentRenderThread (*this); + + renderThread->startThread (6); +} + +void OpenGLComponent::stopRenderThread() +{ + if (renderThread != nullptr) + { + renderThread->stopThread (5000); + renderThread = nullptr; + } + + #if ! JUCE_LINUX + deleteContext(); + #endif +} + //============================================================================== OpenGLComponent::OpenGLComponent (const int flags_) : flags (flags_), contextToShareListsWith (nullptr), needToUpdateViewport (true), needToDeleteContext (false), - threadStarted (false) + threadStarted (false), + needToRepaint (true) { setOpaque (true); + setCachedComponentImage (cachedImage = new OpenGLCachedComponentImage (*this)); componentWatcher = new OpenGLComponentWatcher (*this); - setCachedComponentImage (new OpenGLCachedComponentImage (*this)); } OpenGLComponent::~OpenGLComponent() @@ -492,10 +436,7 @@ void OpenGLComponent::updateContextPosition() Component* const topComp = getTopLevelComponent(); if (topComp->getPeer() != nullptr) - { - const ScopedLock sl (contextLock); updateEmbeddedPosition (topComp->getLocalArea (this, getLocalBounds())); - } } } @@ -508,7 +449,24 @@ void OpenGLComponent::stopBackgroundThread() } } -bool OpenGLComponent::renderAndSwapBuffers() +void OpenGLComponent::triggerRepaint() +{ + // you mustn't set your own cached image object for an OpenGLComponent! + jassert (dynamic_cast (getCachedComponentImage()) == cachedImage); + + cachedImage->triggerRepaint(); +} + +void OpenGLComponent::paint (Graphics&) +{ +} + +unsigned int OpenGLComponent::getFrameBufferID() const +{ + return context != nullptr ? context->getFrameBufferID() : 0; +} + +bool OpenGLComponent::performRender() { const ScopedLock sl (contextLock); @@ -528,28 +486,80 @@ bool OpenGLComponent::renderAndSwapBuffers() } renderOpenGL(); + + if (needToRepaint && (flags & allowSubComponents) != 0) + { + needToRepaint = false; + + contextLock.exit(); // (MM must be locked before the context lock) + MessageManagerLock mmLock (renderThread); + contextLock.enter(); + + if (! mmLock.lockWasGained()) + return false; + + // you mustn't set your own cached image object for an OpenGLComponent! + jassert (dynamic_cast (getCachedComponentImage()) == cachedImage); + + const Rectangle bounds (getLocalBounds()); + OpenGLFrameBuffer& frameBuffer = cachedImage->getFrameBuffer (bounds.getWidth(), bounds.getHeight()); + + { + RectangleList invalid (bounds); + invalid.subtract (cachedImage->validArea); + cachedImage->validArea = bounds; + + if (! invalid.isEmpty()) + { + OpenGLGraphicsContext g (frameBuffer); + g.clipToRectangleList (invalid); + + g.setFill (Colours::transparentBlack); + g.fillRect (bounds, true); + g.setFill (Colours::black); + + paintSelf (g); + + makeCurrentRenderingTarget(); + } + } + + OpenGLHelpers::prepareFor2D (bounds.getWidth(), bounds.getHeight()); + glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + glEnable (GL_BLEND); + glColor4f (1.0f, 1.0f, 1.0f, getAlpha()); + frameBuffer.drawAt (0, (float) (bounds.getHeight() - frameBuffer.getHeight())); + } + swapBuffers(); } return true; } -void OpenGLComponent::triggerRepaint() +void OpenGLComponent::paintSelf (OpenGLGraphicsContext& glRenderer) { - OpenGLCachedComponentImage* const c - = dynamic_cast (getCachedComponentImage()); - - jassert (c != nullptr); // you mustn't set your own cached image object for an OpenGLComponent! + Graphics g (&glRenderer); - if (c != nullptr) - c->triggerRepaint(); -} - -void OpenGLComponent::paint (Graphics&) -{ -} + #if JUCE_ENABLE_REPAINT_DEBUGGING + g.saveState(); + #endif -unsigned int OpenGLComponent::getFrameBufferID() const -{ - return context != nullptr ? context->getFrameBufferID() : 0; + JUCE_TRY + { + paintEntireComponent (g, false); + } + JUCE_CATCH_EXCEPTION + + #if JUCE_ENABLE_REPAINT_DEBUGGING + // enabling this code will fill all areas that get repainted with a colour overlay, to show + // clearly when things are being repainted. + g.restoreState(); + + static Random rng; + g.fillAll (Colour ((uint8) rng.nextInt (255), + (uint8) rng.nextInt (255), + (uint8) rng.nextInt (255), + (uint8) 0x50)); + #endif } diff --git a/modules/juce_opengl/opengl/juce_OpenGLComponent.h b/modules/juce_opengl/opengl/juce_OpenGLComponent.h index c0a866505f..dc0c1a1a21 100644 --- a/modules/juce_opengl/opengl/juce_OpenGLComponent.h +++ b/modules/juce_opengl/opengl/juce_OpenGLComponent.h @@ -34,6 +34,8 @@ typedef Component OpenGLBaseType; #endif +class OpenGLGraphicsContext; + //============================================================================== /** A component that contains an OpenGL canvas. @@ -202,12 +204,6 @@ public: void triggerRepaint(); //============================================================================== - /** Calls the rendering callback, and swaps the buffers afterwards. - This is called automatically by paint() when the component needs to be rendered. - Returns true if the operation succeeded. - */ - virtual bool renderAndSwapBuffers(); - /** This returns a critical section that can be used to lock the current context. Because the context that is used by this component can change, e.g. when the @@ -269,10 +265,11 @@ private: CriticalSection contextLock; OpenGLPixelFormat preferredPixelFormat; - bool needToUpdateViewport, needToDeleteContext, threadStarted; + bool needToUpdateViewport, needToDeleteContext, threadStarted, needToRepaint; class OpenGLCachedComponentImage; friend class OpenGLCachedComponentImage; + OpenGLCachedComponentImage* cachedImage; OpenGLContext* createContext(); void updateContext(); @@ -280,6 +277,10 @@ private: void stopBackgroundThread(); void recreateContextAsync(); void updateEmbeddedPosition (const Rectangle&); + bool performRender(); + void paintSelf (OpenGLGraphicsContext&); + + int renderAndSwapBuffers(); // (This method has been deprecated) JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenGLComponent); }; diff --git a/modules/juce_video/native/juce_win32_DirectShowComponent.cpp b/modules/juce_video/native/juce_win32_DirectShowComponent.cpp index 3286d55e32..69c0bce74e 100644 --- a/modules/juce_video/native/juce_win32_DirectShowComponent.cpp +++ b/modules/juce_video/native/juce_win32_DirectShowComponent.cpp @@ -809,10 +809,7 @@ void DirectShowComponent::paint (Graphics& g) ComponentPeer* const peer = getPeer(); if (peer != nullptr) - { - const Point topLeft (getScreenPosition() - peer->getScreenPosition()); - peer->addMaskedRegion (topLeft.getX(), topLeft.getY(), getWidth(), getHeight()); - } + peer->addMaskedRegion (getScreenBounds() - peer->getScreenPosition()); } else {