Merge lp:~smspillaz/nux/nux.fix_1091589.1 into lp:nux
- nux.fix_1091589.1
- Merge into trunk
Status: | Superseded |
---|---|
Proposed branch: | lp:~smspillaz/nux/nux.fix_1091589.1 |
Merge into: | lp:nux |
Diff against target: |
1795 lines (+1136/-125) 16 files modified
Nux/BaseWindow.cpp (+41/-0) Nux/BaseWindow.h (+16/-0) Nux/View.cpp (+7/-4) Nux/WindowCompositor.cpp (+222/-53) Nux/WindowCompositor.h (+18/-3) Nux/WindowThread.cpp (+110/-8) Nux/WindowThread.h (+50/-1) NuxGraphics/GLDeviceFrameBufferObject.cpp (+20/-5) NuxGraphics/GpuDevice.cpp (+7/-1) NuxGraphics/GpuDeviceTexture.cpp (+7/-1) NuxGraphics/IOpenGLFrameBufferObject.cpp (+7/-1) configure.ac (+2/-3) debian/changelog (+6/-0) tests/gtest-nux-windowcompositor.cpp (+110/-44) tests/gtest-nux-windowthread.cpp (+496/-0) tests/gtest-nuxgraphics-texture.cpp (+17/-1) |
To merge this branch: | bzr merge lp:~smspillaz/nux/nux.fix_1091589.1 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot (community) | continuous-integration | Approve | |
Brandon Schaefer (community) | Approve | ||
Stephen M. Webb (community) | Needs Fixing | ||
Review via email: mp+165772@code.launchpad.net |
This proposal supersedes a proposal from 2013-02-10.
This proposal has been superseded by a proposal from 2013-10-30.
Commit message
Allow embedded clients to specify which windows should be redrawn.
Added some new API to nux to allow embedded clients (eg, compiz) to specify which BaseWindows should be redrawn on a frame. This is done by passing a list of rectangles to nux which represent the redraw region, and nux will mark all intersecting windows as needing re-presenting to the screen. This means that we aren't re-presenting every window to the screen on every frame (bad for performance, and also doesn't work correctly in the buffer-swap case).
Also added API to allow nux to tell the difference between draw and read framebuffers when it plays around with the framebuffer object binding. This is necessary in case the embedded client expects the read framebuffer binding to remain defined even after nux has changed the draw framebuffer binding.
(LP: #1091589)
Description of the change
Allow embedded clients to specify which windows should be redrawn.
Added some new API to nux to allow embedded clients (eg, compiz) to specify which BaseWindows should be redrawn on a frame. This is done by passing a list of rectangles to nux which represent the redraw region, and nux will mark all intersecting windows as needing re-presenting to the screen. This means that we aren't re-presenting every window to the screen on every frame (bad for performance, and also doesn't work correctly in the buffer-swap case).
Also added API to allow nux to tell the difference between draw and read framebuffers when it plays around with the framebuffer object binding. This is necessary in case the embedded client expects the read framebuffer binding to remain defined even after nux has changed the draw framebuffer binding.
(LP: #1091589)
Both APIs are fully tested.
Update: test results here: http://
I was careful to modify phoronix-test-suite to run tests in windowed mode only, and those were the only three tests I was able to get to run in windowed mode. Of particular interest was the fact that the unigine demos had a 5x performance improvement, probably because the driver was spending less time filling redundant pixels from the compositor. In other areas we had a roughly 5FPS boost.
Compiz framerate graph:
http://
You'll see that especially on the last test, it drops off quite a bit on the non buffer_age case, and is generally speaking lower across the board.
Andrea Azzarone (azzar1) wrote : Posted in a previous version of this proposal | # |
Sam Spilsbury (smspillaz) wrote : Posted in a previous version of this proposal | # |
Agree with all points. Will fix later today
On 26/03/2013 8:50 AM, "Andrea Azzarone" <email address hidden> wrote:
> 39 + void BaseWindow:
> 40 + {
> 41 + _present_
> 42 + _last_presented
> GetAbsoluteGeom
> 43 + }
>
> Can we try to find a better name for this function? WasPresented* suggests
> me that the function should return a bool value.
>
> 45 + nux::Geometry const&
> BaseWindow:
> 46 + {
> 47 + return _last_presented
> 48 + }
> 49 +
> 50 + bool BaseWindow:
> 51 + {
> 52 + return _present_
> 53 + }
>
> Can these methods be const?
>
> + for (WindowList:
> 145 + it != _view_window_
> 146 + ++it)
> 147 + {
> 148 + if (it->IsValid())
> 149 + func (*it);
> 150 + }
>
> Why not a range-based for loop? :)
>
> 206 + void WindowComposito
> draw_fbo_object,
> 207 + unsigned int
> read_fbo_object,
> 208 + Geometry
> fbo_geometry)
>
> Geometry const& fbo... ?
>
> 374 + WindowComposito
> 375 +
> window_
> _1, bw, &ptr));
>
> It took me a while to understand what this code was for, maybe we can make
> it more readable.
>
> 406 + for
> (std::vector<
> 407 + m_presentation_
> 408 + it != m_presentation_
> 409 + ++it)
> 410 + {
>
> For range-based loop... :)
>
> Btw logic looks good to me.
> --
> https:/
> You are the owner of lp:~smspillaz/nux/nux.fix_1091589.
>
Sam Spilsbury (smspillaz) wrote : Posted in a previous version of this proposal | # |
Just the only points warranting some discussion:
On Tue, Mar 26, 2013 at 8:50 AM, Andrea Azzarone <email address hidden> wrote:
> 39 + void BaseWindow:
> 40 + {
> 41 + _present_
> 42 + _last_presented
> 43 + }
>
> Can we try to find a better name for this function? WasPresented* suggests me that the function should return a bool value.
Yeah, I remember when I read through this code later I was suprised it didn't.
How about OnPresentedInEm
>
> 374 + WindowComposito
> 375 + window_
>
> It took me a while to understand what this code was for, maybe we can make it more readable.
>
>
Yeah, it could get a bit like that for a codebase that's not really
designed around callbacks. It might actually make sense to wrap this
up in a helper function:
nux::WindowComp
nux::WindowComp
*);
Then the helper function could look something like:
window_
_1, bw, &ptr));
Its basically a glorified:
nux::WindowComp
for (nux::WeakBaseW
if (ptr.get () == raw)
{
weak = ptr;
break;
}
Having it this way would have been preferable, but then it would have
meant exposing the internals of WindowCompositor to BaseWindow, which
was something I wanted to avoid (nux already exposes too many
internals to clients).
What do you think?
--
Sam Spilsbury
Andrea Azzarone (azzar1) wrote : Posted in a previous version of this proposal | # |
> Just the only points warranting some discussion:
>
> On Tue, Mar 26, 2013 at 8:50 AM, Andrea Azzarone <email address hidden> wrote:
> > 39 + void BaseWindow:
> > 40 + {
> > 41 + _present_
> > 42 + _last_presented
> GetAbsoluteGeom
> > 43 + }
> >
> > Can we try to find a better name for this function? WasPresented* suggests
> me that the function should return a bool value.
>
> Yeah, I remember when I read through this code later I was suprised it didn't.
>
> How about OnPresentedInEm
Yeah sounds good to me.
>
> >
> > 374 + WindowComposito
> > 375 + window_
> ndowMatchingRaw, _1, bw, &ptr));
> >
> > It took me a while to understand what this code was for, maybe we can make
> it more readable.
> >
> >
>
> Yeah, it could get a bit like that for a codebase that's not really
> designed around callbacks. It might actually make sense to wrap this
> up in a helper function:
>
> nux::WindowComp
> nux::WindowComp
> *);
>
> Then the helper function could look something like:
>
> window_
> sRawPtr,
> _1, bw, &ptr));
>
> Its basically a glorified:
>
> nux::WindowComp
>
> for (nux::WeakBaseW
> if (ptr.get () == raw)
> {
> weak = ptr;
> break;
> }
>
> Having it this way would have been preferable, but then it would have
> meant exposing the internals of WindowCompositor to BaseWindow, which
> was something I wanted to avoid (nux already exposes too many
> internals to clients).
>
> What do you think?
>
Ok just never mind. That comment was/is not blocking the MP ;)
>
>
> --
> Sam Spilsbury
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:757
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Sam Spilsbury (smspillaz) wrote : Posted in a previous version of this proposal | # |
Okay, so I've talked to Didier about this and we've come up with a small plan of action. We'll need to give this a week solid of QA at the beginning of the S cycle and then make sure that we don't have any AP regressions. That'll happen in about two weeks.
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:758
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:760
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:761
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:762
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:764
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:792
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
MC Return (mc-return) wrote : | # |
News:
http://
AMD's fglrx 13.6 Beta driver now also supports GLX_EXT_buffer_age extension !!! \o/
Stephen M. Webb (bregma) wrote : | # |
This is (obviously) an ABI-breaking change. We need to bump the ABI string, SONAME, package version, and debian/changelog upstream package version at the same time.
This patchset should also include changing configure.ac to bump nux_micro_version to 3, nux_abi_version to, say, 20130530.0, and create a new UNRELEASED entry in debian/changelog for 4.0.3-0ubuntu1.
Sam Spilsbury (smspillaz) wrote : | # |
Okay.
I think I've been bumping the abi in configure.ac for some time now, but
I'll bump the other bits too - I'll be about 2 days with that though as uni
is keeping me busy. Is that OK?
On 29/05/2013 9:51 PM, "Stephen M. Webb" <email address hidden> wrote:
> Review: Needs Fixing
>
> This is (obviously) an ABI-breaking change. We need to bump the ABI
> string, SONAME, package version, and debian/changelog upstream package
> version at the same time.
>
> This patchset should also include changing configure.ac to bump
> nux_micro_version to 3, nux_abi_version to, say, 20130530.0, and create a
> new UNRELEASED entry in debian/changelog for 4.0.3-0ubuntu1.
>
> --
> https:/
> You are the owner of lp:~smspillaz/nux/nux.fix_1091589.1.
>
Sam Spilsbury (smspillaz) wrote : | # |
Thanks for the feedback, done.
- 793. By Sam Spilsbury
-
Bump ABI version and debian/changelog version
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:793
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Brandon Schaefer (brandontschaefer) wrote : | # |
I like this function :)
183 + void WindowComposito
Very functional style! One suggestion would be a different name, possibly. MapFunctionOnAl
547 + if (std::find (m_presentation
548 + m_presentation_
549 + ptr) != m_presentation_
550 + return true;
Might I suggest a simple utility function that will do this? That way you don't have to repeat your self twice and clean that up a bit...(though thats just being nit picky...)
866 + * This is really important. Don't remove it */
867 + result->_OpenGLID = id;
Thats like don't press this button! Now I want to remove it!! (joke no problem here)
No real *needs fixing* just some suggestions. Looking at actually running the branch now :)
Sam Spilsbury (smspillaz) wrote : | # |
On 11/06/2013 7:00 AM, "Brandon Schaefer" <email address hidden>
wrote:
>
> I like this function :)
> 183 + void WindowComposito
&func)
>
> Very functional style! One suggestion would be a different name,
possibly. MapFunctionOnAl
higher order function. (Look up map function if yo want :)
I could, although not everyone knows about map/reduce style. I think the
former is a bit clearer.
>
> 547 + if (std::find (m_presentation
> 548 + m_presentation_
> 549 + ptr) != m_presentation_
> 550 + return true;
>
> Might I suggest a simple utility function that will do this? That way you
don't have to repeat your self twice and clean that up a bit...(though
thats just being nit picky...)
Doable.
>
> 866 + * This is really important. Don't remove it */
> 867 + result->_OpenGLID = id;
>
> Thats like don't press this button! Now I want to remove it!! (joke no
problem here)
Someone removed it a while ago in a cleanup and cost me a day or two
debugging it. I think there's a test in place for it now.
>
> No real *needs fixing* just some suggestions. Looking at actually running
the branch now :)
>
> --
> https:/
> You are the owner of lp:~smspillaz/nux/nux.fix_1091589.1.
Brandon Schaefer (brandontschaefer) wrote : | # |
Cool, well we need to coordinate merging this at the same time as the unity branch, otherwise we are good to go on this branch. Marking as approved, but we need to wait to approved globally until the unity branch is ready :)
- 794. By Sam Spilsbury
-
Merge lp:nux
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:794
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 795. By Sam Spilsbury
-
Split presentation and render into separate functions, call the present
function on any rendered-windows as soon as we need to restore the reference
framebuffer - this will ensure that should we need to do that we can
use the contents of already drawn BaseWindows in the backbuffer as some
part of unity expect. - 796. By Sam Spilsbury
-
Cleanup
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:796
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 797. By Sam Spilsbury
-
Merge lp:nux
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:797
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Unmerged revisions
Preview Diff
1 | === modified file 'Nux/BaseWindow.cpp' |
2 | --- Nux/BaseWindow.cpp 2013-04-08 14:02:32 +0000 |
3 | +++ Nux/BaseWindow.cpp 2013-07-22 17:20:34 +0000 |
4 | @@ -47,6 +47,8 @@ |
5 | : View(NUX_FILE_LINE_PARAM) |
6 | , _paint_layer(new ColorLayer(Color(0xFF707070))) |
7 | , _opacity(1.0f) |
8 | + , _present_in_embedded_mode(false) |
9 | + , _contents_ready_for_presentation(false) |
10 | { |
11 | premultiply = true; |
12 | _name = WindowName; |
13 | @@ -397,6 +399,8 @@ |
14 | } |
15 | else |
16 | { |
17 | + SetEnterFocusInputArea(NULL); |
18 | + |
19 | _entering_hidden_state = true; |
20 | sigHidden.emit(this); |
21 | GetWindowThread()->GetWindowCompositor().sigHiddenViewWindow.emit(this); |
22 | @@ -490,6 +494,43 @@ |
23 | return GetWindowThread()->GetWindowCompositor().GetBackupTextureData(this, width, height, format); |
24 | } |
25 | |
26 | + void BaseWindow::PresentInEmbeddedModeOnThisFrame(bool force) |
27 | + { |
28 | + nuxAssertMsg (GetWindowThread()->IsEmbeddedWindow(), |
29 | + "[BaseWindow::PresentInEmbeddedModeOnThisFrame] only " |
30 | + "supported in embdded mode"); |
31 | + |
32 | + /* Invisible windows are never presented */ |
33 | + if (!IsVisible()) |
34 | + return; |
35 | + |
36 | + if (nux::GetWindowThread()->AddToPresentationList(this, force)) |
37 | + _present_in_embedded_mode = true; |
38 | + } |
39 | + |
40 | + void BaseWindow::OnPresentedInEmbeddedMode() |
41 | + { |
42 | + _present_in_embedded_mode = false; |
43 | + _last_presented_geometry_in_embedded_mode = GetAbsoluteGeometry(); |
44 | + } |
45 | + |
46 | + nux::Geometry const& BaseWindow::LastPresentedGeometryInEmbeddedMode() const |
47 | + { |
48 | + return _last_presented_geometry_in_embedded_mode; |
49 | + } |
50 | + |
51 | + bool BaseWindow::AllowPresentationInEmbeddedMode() const |
52 | + { |
53 | + return _present_in_embedded_mode; |
54 | + } |
55 | + |
56 | + void BaseWindow::PrepareParentRedirectedView() |
57 | + { |
58 | + Area::PrepareParentRedirectedView(); |
59 | + if (GetWindowThread()->IsEmbeddedWindow()) |
60 | + PresentInEmbeddedModeOnThisFrame(); |
61 | + } |
62 | + |
63 | void BaseWindow::SetEnterFocusInputArea(InputArea *input_area) |
64 | { |
65 | if (_enter_focus_input_area) |
66 | |
67 | === modified file 'Nux/BaseWindow.h' |
68 | --- Nux/BaseWindow.h 2012-11-12 20:59:56 +0000 |
69 | +++ Nux/BaseWindow.h 2013-07-22 17:20:34 +0000 |
70 | @@ -188,6 +188,14 @@ |
71 | return _name; |
72 | } |
73 | |
74 | + bool RedrawnContentsPendingPresentation(); |
75 | + void PresentInEmbeddedModeOnThisFrame(bool force = false); |
76 | + void OnPresentedInEmbeddedMode(); |
77 | + bool AllowPresentationInEmbeddedMode() const; |
78 | + nux::Geometry const& LastPresentedGeometryInEmbeddedMode() const; |
79 | + |
80 | + void PrepareParentRedirectedView(); |
81 | + |
82 | #ifdef NUX_GESTURES_SUPPORT |
83 | virtual Area* GetInputAreaHitByGesture(const nux::GestureEvent &event); |
84 | #endif |
85 | @@ -261,6 +269,14 @@ |
86 | bool _child_need_redraw; //!<True is there is a child of the BaseWindow that needs to be redrawn; |
87 | float _opacity; |
88 | |
89 | + bool _present_in_embedded_mode; //!<True if we should draw this window's |
90 | + // backing texture to the screen on the |
91 | + // next frame |
92 | + nux::Geometry _last_presented_geometry_in_embedded_mode; |
93 | + |
94 | + bool _contents_ready_for_presentation; //!<True if this window's contents has just been |
95 | + // redrawn and it is awaiting presentation |
96 | + |
97 | friend class PopUpWindow; |
98 | |
99 | friend class WindowThread; |
100 | |
101 | === modified file 'Nux/View.cpp' |
102 | --- Nux/View.cpp 2013-04-08 14:02:32 +0000 |
103 | +++ Nux/View.cpp 2013-07-22 17:20:34 +0000 |
104 | @@ -425,6 +425,13 @@ |
105 | |
106 | void View::QueueDraw() |
107 | { |
108 | + // Report to a parent view with redirect_rendering_to_texture_ set to true that one of its children |
109 | + // needs to be redrawn. |
110 | + // |
111 | + // We should always do this, as the conditions for parent rendering may have |
112 | + // changed between child QueueDraw calls (eg window visibility) |
113 | + PrepareParentRedirectedView(); |
114 | + |
115 | if (draw_cmd_queued_) |
116 | return; |
117 | |
118 | @@ -435,10 +442,6 @@ |
119 | application->RequestRedraw(); |
120 | } |
121 | |
122 | - // Report to a parent view with redirect_rendering_to_texture_ set to true that one of its children |
123 | - // needs to be redrawn. |
124 | - PrepareParentRedirectedView(); |
125 | - |
126 | if (view_layout_) |
127 | { |
128 | // If this view has requested a draw, then all of it children in the view_layout_ |
129 | |
130 | === modified file 'Nux/WindowCompositor.cpp' |
131 | --- Nux/WindowCompositor.cpp 2013-05-28 10:26:28 +0000 |
132 | +++ Nux/WindowCompositor.cpp 2013-07-22 17:20:34 +0000 |
133 | @@ -41,8 +41,11 @@ |
134 | DECLARE_LOGGER(logger, "nux.window"); |
135 | |
136 | WindowCompositor::WindowCompositor(WindowThread* window_thread) |
137 | - : reference_fbo_(0) |
138 | + : draw_reference_fbo_(0) |
139 | + , read_reference_fbo_(0) |
140 | , window_thread_(window_thread) |
141 | + , _currently_rendering_windows(NULL) |
142 | + , _current_global_clip_rect(NULL) |
143 | { |
144 | m_OverlayWindow = NULL; |
145 | _tooltip_window = NULL; |
146 | @@ -209,7 +212,17 @@ |
147 | WindowList::iterator window_it; |
148 | for (window_it = _view_window_list.begin(); window_it != _view_window_list.end(); ++window_it) |
149 | { |
150 | - if ((*window_it).IsValid() && (*window_it)->IsVisible()) |
151 | + // Since the mouse is really an input-level thing, we want to know |
152 | + // if the underlying input window is enabled or if the window is |
153 | + // visible |
154 | + |
155 | + if (!window_it->IsValid()) |
156 | + continue; |
157 | + |
158 | + bool visible_or_input_enabled = (*window_it)->InputWindowEnabled() || |
159 | + (*window_it)->IsVisible(); |
160 | + |
161 | + if (visible_or_input_enabled) |
162 | { |
163 | Area* area = (*window_it)->FindAreaUnderMouse(mouse_position, event_type); |
164 | if (area) |
165 | @@ -1341,6 +1354,50 @@ |
166 | } |
167 | } |
168 | |
169 | + namespace |
170 | + { |
171 | + void |
172 | + AssignWeakBaseWindowMatchingRaw(WindowCompositor::WeakBaseWindowPtr const& w, |
173 | + BaseWindow* bw, |
174 | + WindowCompositor::WeakBaseWindowPtr *ptr) |
175 | + { |
176 | + if (w.IsValid() && |
177 | + w.GetPointer() == bw) |
178 | + *ptr = w; |
179 | + } |
180 | + } |
181 | + |
182 | + WindowCompositor::WeakBaseWindowPtr WindowCompositor::FindWeakBaseWindowPtrForRawPtr(nux::BaseWindow *raw) |
183 | + { |
184 | + using namespace std::placeholders; |
185 | + |
186 | + WeakBaseWindowPtr weak; |
187 | + OnAllBaseWindows(std::bind(AssignWeakBaseWindowMatchingRaw, _1, raw, &weak)); |
188 | + return weak; |
189 | + } |
190 | + |
191 | + void WindowCompositor::OnAllBaseWindows(const WindowMutatorFunc &func) |
192 | + { |
193 | + for (WeakBaseWindowPtr const& ptr : _view_window_list) |
194 | + { |
195 | + if (ptr.IsValid()) |
196 | + func(ptr); |
197 | + } |
198 | + |
199 | + for (WeakBaseWindowPtr const& ptr : _view_window_list) |
200 | + if (ptr.IsValid()) |
201 | + func(ptr); |
202 | + |
203 | + if (m_MenuWindow.IsValid()) |
204 | + func(m_MenuWindow); |
205 | + |
206 | + if (_tooltip_window.IsValid()) |
207 | + func(_tooltip_window); |
208 | + |
209 | + if (m_OverlayWindow.IsValid()) |
210 | + func(m_OverlayWindow); |
211 | + } |
212 | + |
213 | void WindowCompositor::Draw(bool SizeConfigurationEvent, bool force_draw) |
214 | { |
215 | inside_rendering_cycle_ = true; |
216 | @@ -1501,6 +1558,64 @@ |
217 | GetPainter().EmptyBackgroundStack(); |
218 | } |
219 | |
220 | + void WindowCompositor::PresentAnyReadyWindows() |
221 | + { |
222 | + if (!_currently_rendering_windows || |
223 | + !_current_global_clip_rect) |
224 | + return; |
225 | + |
226 | + GraphicsEngine& graphics_engine = window_thread_->GetGraphicsEngine(); |
227 | + |
228 | + // Present all buffers to the screen |
229 | + graphics_engine.ApplyClippingRectangle(); |
230 | + CHECKGL(glDepthMask(GL_FALSE)); |
231 | + |
232 | + WindowList &windows = *_currently_rendering_windows; |
233 | + Geometry &global_clip_rect = *_current_global_clip_rect; |
234 | + |
235 | + for (WindowList::iterator it = windows.begin(), end = windows.end(); it != end; ++it) |
236 | + { |
237 | + WeakBaseWindowPtr& window_ptr = *it; |
238 | + if (window_ptr.IsNull()) |
239 | + continue; |
240 | + |
241 | + BaseWindow* window = window_ptr.GetPointer(); |
242 | + |
243 | + if (window->IsVisible()) |
244 | + { |
245 | + if (global_clip_rect.Intersect(window->GetGeometry()).IsNull()) |
246 | + { |
247 | + // The global clipping area can be seen as a per monitor clipping |
248 | + // region. It is mostly used in embedded mode with compiz. If we |
249 | + // get here, it means that the BaseWindow we want to render is not |
250 | + // in area of the monitor that compiz is currently rendering. So |
251 | + // skip it. |
252 | + continue; |
253 | + } |
254 | + |
255 | + RenderTargetTextures& rt = GetWindowBuffer(window); |
256 | + |
257 | + if (rt.color_rt.IsValid()) |
258 | + { |
259 | + /* Already been presented */ |
260 | + if (!window->_contents_ready_for_presentation) |
261 | + continue; |
262 | + |
263 | + /* Caller doesn't want us to render this yet */ |
264 | + if (GetWindowThread()->IsEmbeddedWindow() && |
265 | + !window->AllowPresentationInEmbeddedMode()) |
266 | + continue; |
267 | + |
268 | + // Nux is done rendering a BaseWindow into a texture. The previous call to Deactivate |
269 | + // has cancelled any opengl framebuffer object that was set. |
270 | + PresentBufferToScreen(rt.color_rt, window->GetBaseX(), window->GetBaseY(), false, false, window->GetOpacity(), window->premultiply()); |
271 | + |
272 | + window->_contents_ready_for_presentation = false; |
273 | + } |
274 | + } |
275 | + } |
276 | + } |
277 | + |
278 | void WindowCompositor::RenderTopViews(bool force_draw, |
279 | WindowList& windows_to_render, |
280 | bool drawModal) |
281 | @@ -1512,13 +1627,17 @@ |
282 | GraphicsEngine& graphics_engine = window_thread_->GetGraphicsEngine(); |
283 | unsigned int window_width = graphics_engine.GetWindowWidth(); |
284 | unsigned int window_height = graphics_engine.GetWindowHeight(); |
285 | - GetGraphicsDisplay()->GetGpuDevice()->DeactivateFrameBuffer(); |
286 | graphics_engine.SetViewport(0, 0, window_width, window_height); |
287 | graphics_engine.EmptyClippingRegion(); |
288 | |
289 | Geometry global_clip_rect = graphics_engine.GetScissorRect(); |
290 | global_clip_rect.y = window_height - global_clip_rect.y - global_clip_rect.height; |
291 | |
292 | + _current_global_clip_rect = &global_clip_rect; |
293 | + |
294 | + // We don't need to restore framebuffers if we didn't update any windows |
295 | + bool updated_any_windows = false; |
296 | + |
297 | // Always make a copy of the windows to render. We have no control over |
298 | // the windows we are actually drawing. It has been observed that some |
299 | // windows modify the windows stack during the draw process. |
300 | @@ -1530,6 +1649,9 @@ |
301 | // list, lets reverse it as we are constructing, as we want to draw the |
302 | // windows from back to front. |
303 | WindowList windows(windows_to_render.rbegin(), windows_to_render.rend()); |
304 | + |
305 | + _currently_rendering_windows = &windows; |
306 | + |
307 | for (WindowList::iterator it = windows.begin(), end = windows.end(); it != end; ++it) |
308 | { |
309 | WeakBaseWindowPtr& window_ptr = *it; |
310 | @@ -1537,6 +1659,7 @@ |
311 | continue; |
312 | |
313 | BaseWindow* window = window_ptr.GetPointer(); |
314 | + |
315 | if (!drawModal && window->IsModal()) |
316 | continue; |
317 | |
318 | @@ -1594,25 +1717,15 @@ |
319 | } |
320 | |
321 | RenderTopViewContent(window, force_draw); |
322 | - } |
323 | |
324 | - if (rt.color_rt.IsValid()) |
325 | - { |
326 | m_FrameBufferObject->Deactivate(); |
327 | - |
328 | - // Nux is done rendering a BaseWindow into a texture. The previous call to Deactivate |
329 | - // has cancelled any opengl framebuffer object that was set. |
330 | - |
331 | - CHECKGL(glDepthMask(GL_FALSE)); |
332 | - { |
333 | - graphics_engine.ApplyClippingRectangle(); |
334 | - PresentBufferToScreen(rt.color_rt, window->GetBaseX(), window->GetBaseY(), false, false, window->GetOpacity(), window->premultiply()); |
335 | - } |
336 | CHECKGL(glDepthMask(GL_TRUE)); |
337 | graphics_engine.GetRenderStates().SetBlend(false); |
338 | + updated_any_windows = true; |
339 | } |
340 | |
341 | window->_child_need_redraw = false; |
342 | + window->_contents_ready_for_presentation = true; |
343 | } |
344 | else |
345 | { |
346 | @@ -1622,7 +1735,27 @@ |
347 | } |
348 | } |
349 | |
350 | - m_FrameBufferObject->Deactivate(); |
351 | + /* If any windows were updated, then we need to rebind our |
352 | + * reference framebuffer */ |
353 | + if (updated_any_windows) |
354 | + { |
355 | + if (GetWindowThread()->IsEmbeddedWindow()) |
356 | + { |
357 | + // Restore the reference framebuffer |
358 | + if (!RestoreReferenceFramebuffer()) |
359 | + { |
360 | + nuxDebugMsg("[WindowCompositor::RenderTopViews] Setting the Reference fbo has failed."); |
361 | + } |
362 | + } |
363 | + else |
364 | + GetGraphicsDisplay()->GetGpuDevice()->DeactivateFrameBuffer(); |
365 | + } |
366 | + |
367 | + /* Present any windows which haven't yet been presented */ |
368 | + PresentAnyReadyWindows(); |
369 | + |
370 | + _currently_rendering_windows = NULL; |
371 | + _current_global_clip_rect = NULL; |
372 | } |
373 | |
374 | void WindowCompositor::RenderMainWindowComposition(bool force_draw) |
375 | @@ -1720,23 +1853,8 @@ |
376 | m_FrameBufferObject->SetDepthTextureAttachment(m_MainDepthRT, 0); |
377 | m_FrameBufferObject->Activate(); |
378 | } |
379 | - else |
380 | - { |
381 | - if (GetWindowThread()->IsEmbeddedWindow() && reference_fbo_) |
382 | - { |
383 | - // In the context of Unity, we may want Nux to restore a specific fbo and render the |
384 | - // BaseWindow texture into it. That fbo is called a reference framebuffer object. if a |
385 | - // Reference framebuffer object is present, Nux sets it. |
386 | - if (!RestoreReferenceFramebuffer()) |
387 | - { |
388 | - nuxDebugMsg("[WindowCompositor::RenderTopViews] Setting the Reference fbo has failed."); |
389 | - } |
390 | - } |
391 | - else |
392 | - { |
393 | - GetGraphicsDisplay()->GetGpuDevice()->DeactivateFrameBuffer(); |
394 | - } |
395 | - } |
396 | + |
397 | + // Reference framebuffer is already restored |
398 | |
399 | window_thread_->GetGraphicsEngine().EmptyClippingRegion(); |
400 | window_thread_->GetGraphicsEngine().SetOpenGLClippingRectangle(0, 0, window_width, window_height); |
401 | @@ -2140,11 +2258,22 @@ |
402 | |
403 | nuxAssert(buffer_width >= 1); |
404 | nuxAssert(buffer_height >= 1); |
405 | - // Restore Main Frame Buffer |
406 | - m_FrameBufferObject->FormatFrameBufferObject(buffer_width, buffer_height, BITFMT_R8G8B8A8); |
407 | - m_FrameBufferObject->SetTextureAttachment(0, m_MainColorRT, 0); |
408 | - m_FrameBufferObject->SetDepthTextureAttachment(m_MainDepthRT, 0); |
409 | - m_FrameBufferObject->Activate(); |
410 | + // Restore Main Frame Buffer if not in embedded mode |
411 | + if (!GetWindowThread()->IsEmbeddedWindow()) |
412 | + { |
413 | + m_FrameBufferObject->FormatFrameBufferObject(buffer_width, buffer_height, BITFMT_R8G8B8A8); |
414 | + m_FrameBufferObject->SetTextureAttachment(0, m_MainColorRT, 0); |
415 | + m_FrameBufferObject->SetDepthTextureAttachment(m_MainDepthRT, 0); |
416 | + m_FrameBufferObject->Activate(); |
417 | + } |
418 | + else |
419 | + { |
420 | + // Restore reference framebuffer |
421 | + RestoreReferenceFramebuffer(); |
422 | + |
423 | + // Present any ready windows |
424 | + PresentAnyReadyWindows(); |
425 | + } |
426 | |
427 | window_thread_->GetGraphicsEngine().SetViewport(0, 0, buffer_width, buffer_height); |
428 | window_thread_->GetGraphicsEngine().SetOrthographicProjectionMatrix(buffer_width, buffer_height); |
429 | @@ -2429,9 +2558,12 @@ |
430 | return (*keyboard_grab_stack_.begin()); |
431 | } |
432 | |
433 | - void WindowCompositor::SetReferenceFramebuffer(unsigned int fbo_object, Geometry fbo_geometry) |
434 | + void WindowCompositor::SetReferenceFramebuffer(unsigned int draw_fbo_object, |
435 | + unsigned int read_fbo_object, |
436 | + Geometry const& fbo_geometry) |
437 | { |
438 | - reference_fbo_ = fbo_object; |
439 | + draw_reference_fbo_ = draw_fbo_object; |
440 | + read_reference_fbo_ = read_fbo_object; |
441 | reference_fbo_geometry_ = fbo_geometry; |
442 | } |
443 | |
444 | @@ -2497,7 +2629,7 @@ |
445 | return ok; |
446 | } |
447 | |
448 | - void SetReferenceFramebufferViewport (const nux::Geometry &reference_fbo_geometry_) |
449 | + void SetReferenceFramebufferViewport(const nux::Geometry &reference_fbo_geometry_) |
450 | { |
451 | CHECKGL(glViewport(reference_fbo_geometry_.x, |
452 | reference_fbo_geometry_.y, |
453 | @@ -2508,24 +2640,53 @@ |
454 | |
455 | bool WindowCompositor::RestoreReferenceFramebuffer() |
456 | { |
457 | - if (!reference_fbo_) |
458 | - return false; |
459 | - |
460 | // It is assumed that the reference fbo contains valid textures. |
461 | // Nux does the following: |
462 | // - Bind the reference fbo (reference_fbo_) |
463 | // - Call glDrawBuffer with GL_COLOR_ATTACHMENT0 |
464 | // - Set the opengl viewport size (reference_fbo_geometry_) |
465 | |
466 | - CHECKGL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, reference_fbo_)); |
467 | -#ifndef NUX_OPENGLES_20 |
468 | - CHECKGL(glDrawBuffer(GL_COLOR_ATTACHMENT0)); |
469 | - CHECKGL(glReadBuffer(GL_COLOR_ATTACHMENT0)); |
470 | -#endif |
471 | - |
472 | - SetReferenceFramebufferViewport (reference_fbo_geometry_); |
473 | - |
474 | - return CheckExternalFramebufferStatus (GL_FRAMEBUFFER_EXT); |
475 | +#ifndef NUX_OPENGLES_20 |
476 | + CHECKGL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, draw_reference_fbo_)); |
477 | + CHECKGL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, read_reference_fbo_)); |
478 | + if (draw_reference_fbo_) |
479 | + { |
480 | + CHECKGL(glDrawBuffer(GL_COLOR_ATTACHMENT0)); |
481 | + } |
482 | + else |
483 | + { |
484 | + CHECKGL(glDrawBuffer(GL_BACK)); |
485 | + } |
486 | + |
487 | + if (read_reference_fbo_) |
488 | + { |
489 | + CHECKGL(glReadBuffer(GL_COLOR_ATTACHMENT0)); |
490 | + } |
491 | + else |
492 | + { |
493 | + CHECKGL(glReadBuffer(GL_BACK)); |
494 | + } |
495 | +#else |
496 | + nuxAssertMsg(draw_reference_fbo_ == read_reference_fbo_, |
497 | + "[WindowCompositor::RestoreReferenceFramebuffer]: OpenGL|ES does not"\ |
498 | + " support separate draw and read framebuffer bindings, using the supplied"\ |
499 | + " draw binding"); |
500 | + CHECKGL(glBindFramebufferEXT(GL_FRAMEBUFFER, draw_reference_fbo_)); |
501 | +#endif |
502 | + |
503 | + SetReferenceFramebufferViewport(reference_fbo_geometry_); |
504 | + |
505 | +#ifndef NUX_OPENGLES_20 |
506 | + int restore_status = |
507 | + (!draw_reference_fbo_ || |
508 | + CheckExternalFramebufferStatus(GL_DRAW_FRAMEBUFFER_EXT)) && |
509 | + (!read_reference_fbo_ || |
510 | + CheckExternalFramebufferStatus(GL_READ_FRAMEBUFFER_EXT)); |
511 | +#else |
512 | + int restore_status = CheckExternalFramebufferStatus(GL_FRAMEBUFFER); |
513 | +#endif |
514 | + |
515 | + return restore_status; |
516 | } |
517 | |
518 | void WindowCompositor::RestoreMainFramebuffer() |
519 | @@ -2533,6 +2694,14 @@ |
520 | // This is a bit inefficient as we unbind and then rebind |
521 | nux::GetGraphicsDisplay()->GetGpuDevice()->DeactivateFrameBuffer (); |
522 | RestoreReferenceFramebuffer (); |
523 | + |
524 | + /* Present any ready windows after restoring |
525 | + * the reference framebuffer. This ensures that if |
526 | + * we need to restore the reference framebuffer to |
527 | + * get access to its contents through glCopyTexSubImage2D |
528 | + * that it will also have any rendered views in it too |
529 | + */ |
530 | + PresentAnyReadyWindows(); |
531 | } |
532 | |
533 | #ifdef NUX_GESTURES_SUPPORT |
534 | |
535 | === modified file 'Nux/WindowCompositor.h' |
536 | --- Nux/WindowCompositor.h 2013-04-29 23:33:12 +0000 |
537 | +++ Nux/WindowCompositor.h 2013-07-22 17:20:34 +0000 |
538 | @@ -23,6 +23,8 @@ |
539 | #ifndef WINDOWCOMPOSITOR_H |
540 | #define WINDOWCOMPOSITOR_H |
541 | |
542 | +#include <functional> |
543 | + |
544 | #include "BaseWindow.h" |
545 | |
546 | #include <sigc++/trackable.h> |
547 | @@ -53,6 +55,7 @@ |
548 | { |
549 | public: |
550 | typedef ObjectWeakPtr<BaseWindow> WeakBaseWindowPtr; |
551 | + typedef std::function <void(const WeakBaseWindowPtr &)> WindowMutatorFunc; |
552 | |
553 | WindowCompositor(WindowThread* window_thread); |
554 | ~WindowCompositor(); |
555 | @@ -115,6 +118,8 @@ |
556 | */ |
557 | InputArea* GetKeyFocusArea(); |
558 | |
559 | + void OnAllBaseWindows(const WindowMutatorFunc &); |
560 | + |
561 | //! Signal emitted when a BaseWindow becomes visible. |
562 | /*! |
563 | This signal is emitted after the BaseWindow has emitted it own sigVisible signal. |
564 | @@ -239,10 +244,11 @@ |
565 | restored after Nux completes it rendering. The external fbo is used only in embedded mode. \n |
566 | If the fbo_object parameter 0, then the reference fbo is invalid and will not be used. |
567 | |
568 | - @param fbo_object The opengl index of the fbo. |
569 | + @param draw_fbo_object The opengl index of the GL_DRAW_FRAMEBUFFER_EXT. |
570 | + @param read_fbo_object The opengl index of the GL_READ_FRAMEBUFFER_EXT. |
571 | @param fbo_geometry The geometry of the fbo. |
572 | */ |
573 | - void SetReferenceFramebuffer(unsigned int fbo_object, Geometry fbo_geometry); |
574 | + void SetReferenceFramebuffer(unsigned int draw_fbo_object, unsigned int read_fbo_object, const Geometry &fbo_geometry); |
575 | |
576 | /*! |
577 | Bind the reference opengl framebuffer object. |
578 | @@ -408,6 +414,9 @@ |
579 | #endif |
580 | |
581 | private: |
582 | + |
583 | + WeakBaseWindowPtr FindWeakBaseWindowPtrForRawPtr(nux::BaseWindow *); |
584 | + |
585 | //! Render the interface. |
586 | void Draw(bool SizeConfigurationEvent, bool force_draw); |
587 | |
588 | @@ -424,6 +433,8 @@ |
589 | */ |
590 | void RenderTopViews(bool force_draw, std::list< ObjectWeakPtr<BaseWindow> >& WindowList, bool draw_modal); |
591 | |
592 | + void PresentAnyReadyWindows(); |
593 | + |
594 | //! Render the content of a top view. |
595 | void RenderTopViewContent(BaseWindow* window, bool force_draw); |
596 | |
597 | @@ -534,7 +545,8 @@ |
598 | int m_TooltipY; |
599 | |
600 | //! The fbo to restore after Nux rendering in embedded mode. |
601 | - unsigned int reference_fbo_; |
602 | + unsigned int draw_reference_fbo_; |
603 | + unsigned int read_reference_fbo_; |
604 | Geometry reference_fbo_geometry_; |
605 | |
606 | //! True if the platform has support for depth textures. |
607 | @@ -571,6 +583,9 @@ |
608 | std::unique_ptr<GestureBroker> gesture_broker_; |
609 | #endif |
610 | |
611 | + WindowList *_currently_rendering_windows; |
612 | + Geometry *_current_global_clip_rect; |
613 | + |
614 | //! Perform some action before destruction. |
615 | /*! |
616 | Perform some action before destruction. This function should only be |
617 | |
618 | === modified file 'Nux/WindowThread.cpp' |
619 | --- Nux/WindowThread.cpp 2013-04-13 21:21:01 +0000 |
620 | +++ Nux/WindowThread.cpp 2013-07-22 17:20:34 +0000 |
621 | @@ -19,6 +19,8 @@ |
622 | * |
623 | */ |
624 | |
625 | +#include <functional> |
626 | + |
627 | #include "Nux.h" |
628 | #include "Layout.h" |
629 | #include "NuxCore/Logger.h" |
630 | @@ -50,6 +52,7 @@ |
631 | |
632 | WindowThread::WindowThread(const char *WindowTitle, int width, int height, AbstractThread *Parent, bool Modal) |
633 | : AbstractThread(Parent) |
634 | + , foreign_frame_frozen_(false) |
635 | , window_initial_width_(width) |
636 | , window_initial_height_(height) |
637 | , window_title_(WindowTitle) |
638 | @@ -1389,6 +1392,58 @@ |
639 | return m_dirty_areas; |
640 | } |
641 | |
642 | + bool WindowThread::AddToPresentationList(BaseWindow *bw, |
643 | + bool force = false) |
644 | + { |
645 | + RequestRedraw(); |
646 | + WindowCompositor::WeakBaseWindowPtr ptr(window_compositor_->FindWeakBaseWindowPtrForRawPtr(bw)); |
647 | + |
648 | + if (!ptr.IsValid()) |
649 | + return false; |
650 | + |
651 | + if (force || |
652 | + !foreign_frame_frozen_) |
653 | + { |
654 | + if (std::find(m_presentation_list_embedded.begin(), |
655 | + m_presentation_list_embedded.end(), |
656 | + ptr) != m_presentation_list_embedded.end()) |
657 | + return true; |
658 | + |
659 | + m_presentation_list_embedded.push_back(ptr); |
660 | + return true; |
661 | + } |
662 | + else |
663 | + { |
664 | + if (std::find(m_presentation_list_embedded_next_frame.begin(), |
665 | + m_presentation_list_embedded_next_frame.end(), |
666 | + ptr) != m_presentation_list_embedded_next_frame.end()) |
667 | + return false; |
668 | + |
669 | + m_presentation_list_embedded_next_frame.push_back(ptr); |
670 | + return false; |
671 | + } |
672 | + } |
673 | + |
674 | + std::vector<nux::Geometry> WindowThread::GetPresentationListGeometries() |
675 | + { |
676 | + std::vector<nux::Geometry> presentation_geometries; |
677 | + for (WindowCompositor::WeakBaseWindowPtr const& base_window : m_presentation_list_embedded) |
678 | + { |
679 | + if (base_window.IsValid()) |
680 | + { |
681 | + nux::Geometry const& abs_geom(base_window->GetAbsoluteGeometry()); |
682 | + nux::Geometry const& last_geom(base_window->LastPresentedGeometryInEmbeddedMode()); |
683 | + presentation_geometries.push_back(abs_geom); |
684 | + if (abs_geom != last_geom) |
685 | + { |
686 | + if (!last_geom.IsNull()) |
687 | + presentation_geometries.push_back(last_geom); |
688 | + } |
689 | + } |
690 | + } |
691 | + return presentation_geometries; |
692 | + } |
693 | + |
694 | bool WindowThread::IsEmbeddedWindow() |
695 | { |
696 | return embedded_window_; |
697 | @@ -1529,6 +1584,32 @@ |
698 | return request_draw_cycle_to_host_wm; |
699 | } |
700 | |
701 | + namespace { |
702 | + |
703 | + void PresentOnBaseWindowIntersectsRect(ObjectWeakPtr<BaseWindow> const& w, |
704 | + Geometry const& rect) |
705 | + { |
706 | + Geometry inter = rect.Intersect(w->GetAbsoluteGeometry()); |
707 | + if (!inter.IsNull()) |
708 | + w->PresentInEmbeddedModeOnThisFrame(true); |
709 | + } |
710 | + |
711 | + void MarkWindowUnpresented(const ObjectWeakPtr<BaseWindow> &w) |
712 | + { |
713 | + w->OnPresentedInEmbeddedMode(); |
714 | + } |
715 | + |
716 | + } |
717 | + |
718 | + void WindowThread::PresentWindowsIntersectingGeometryOnThisFrame(const Geometry &rect) |
719 | + { |
720 | + using namespace std::placeholders; |
721 | + nuxAssertMsg(IsEmbeddedWindow(), |
722 | + "[WindowThread::PresentWindowIntersectingGeometryOnThisFrame] " |
723 | + "can only be called inside an embedded window"); |
724 | + window_compositor_->OnAllBaseWindows(std::bind(PresentOnBaseWindowIntersectsRect, _1, rect)); |
725 | + } |
726 | + |
727 | void WindowThread::RenderInterfaceFromForeignCmd(Geometry *clip) |
728 | { |
729 | nuxAssertMsg(IsEmbeddedWindow() == true, "[WindowThread::RenderInterfaceFromForeignCmd] You can only call RenderInterfaceFromForeignCmd if the window was created with CreateFromForeignWindow."); |
730 | @@ -1568,17 +1649,38 @@ |
731 | |
732 | CHECKGL( glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE)); |
733 | |
734 | - graphics_display_->GetGpuDevice()->DeactivateFrameBuffer(); |
735 | IOpenGLShaderProgram::SetShaderTracking(false); |
736 | - |
737 | - if (IsEmbeddedWindow() && window_compositor_->reference_fbo_) |
738 | + } |
739 | + |
740 | + void WindowThread::ForeignFrameEnded() |
741 | + { |
742 | + using namespace std::placeholders; |
743 | + nuxAssertMsg(IsEmbeddedWindow(), |
744 | + "[WindowThread::ForeignFrameEnded] " |
745 | + "can only be called inside an embedded window"); |
746 | + window_compositor_->OnAllBaseWindows(std::bind(MarkWindowUnpresented, _1)); |
747 | + m_presentation_list_embedded.clear(); |
748 | + |
749 | + foreign_frame_frozen_ = false; |
750 | + |
751 | + /* Move all the BaseWindows in m_presentation_list_embedded_next_frame |
752 | + * to m_presentation_list_embedded and mark them for presentation |
753 | + */ |
754 | + for (std::vector<WindowCompositor::WeakBaseWindowPtr>::iterator it = |
755 | + m_presentation_list_embedded_next_frame.begin(); |
756 | + it != m_presentation_list_embedded_next_frame.end(); |
757 | + ++it) |
758 | { |
759 | - // Restore the reference framebuffer |
760 | - if (!window_compositor_->RestoreReferenceFramebuffer()) |
761 | - { |
762 | - nuxDebugMsg("[WindowCompositor::RenderTopViews] Setting the Reference fbo has failed."); |
763 | - } |
764 | + if (it->IsValid()) |
765 | + (*it)->PresentInEmbeddedModeOnThisFrame(); |
766 | } |
767 | + |
768 | + m_presentation_list_embedded_next_frame.clear(); |
769 | + } |
770 | + |
771 | + void WindowThread::ForeignFrameCutoff() |
772 | + { |
773 | + foreign_frame_frozen_ = true; |
774 | } |
775 | |
776 | int WindowThread::InstallEventInspector(EventInspector function, void* data) |
777 | |
778 | === modified file 'Nux/WindowThread.h' |
779 | --- Nux/WindowThread.h 2013-04-10 18:56:19 +0000 |
780 | +++ Nux/WindowThread.h 2013-07-22 17:20:34 +0000 |
781 | @@ -32,6 +32,7 @@ |
782 | namespace nux |
783 | { |
784 | |
785 | + class BaseWindow; |
786 | class WindowThread; |
787 | class Layout; |
788 | class HLayout; |
789 | @@ -227,6 +228,17 @@ |
790 | #endif |
791 | |
792 | /*! |
793 | + In embedded mode, allow presentation on any windows intersecting this |
794 | + rect. The effect of this is culmulative for the frame, so it can be |
795 | + called multiple times with many different rects until |
796 | + RenderInterfaceFromForeignCmd is called. |
797 | + \sa IsEmbeddedWindow |
798 | + |
799 | + @param rect Region of the display to consider for presenting windows |
800 | + */ |
801 | + void PresentWindowsIntersectingGeometryOnThisFrame(const Geometry &rect); |
802 | + |
803 | + /*! |
804 | Render the interface. This command is send from the pluging when the window thread is embedded. |
805 | The clip region matches the surface of one single monitor screen, or a region inside that screen. |
806 | \sa IsEmbeddedWindow. |
807 | @@ -235,6 +247,19 @@ |
808 | */ |
809 | void RenderInterfaceFromForeignCmd(Geometry *clip); |
810 | |
811 | + /*! |
812 | + Used to mark the end of the foreign frame. All calls to PresentInEmbeddedModeOnThisFrame |
813 | + are now redirected to this upcoming frame where we will be called next. |
814 | + */ |
815 | + void ForeignFrameEnded(); |
816 | + |
817 | + /*! |
818 | + Used to mark the cutoff point where all calls to PresentInEmbeddedModeOnThisFrame |
819 | + should be effective on the next frame, and not this one, because the parent context |
820 | + has stopped tracking damage events for this frame |
821 | + */ |
822 | + void ForeignFrameCutoff(); |
823 | + |
824 | #if !defined(NUX_MINIMAL) |
825 | /*! |
826 | Add a timeline to our window |
827 | @@ -319,12 +344,19 @@ |
828 | |
829 | bool IsRedrawNeeded() const; |
830 | |
831 | + // DrawList - this is a maintained list of areas that will |
832 | + // be completely redraw on the next frame |
833 | void AddToDrawList(View *view); |
834 | - |
835 | void ClearDrawList(); |
836 | |
837 | std::vector<Geometry> const& GetDrawList() const; |
838 | |
839 | + // PresentationList - this is a maintained list of areas that |
840 | + // will be presented to the reference framebuffer or backbuffer |
841 | + // in embedded mode on the next frame |
842 | + bool AddToPresentationList(nux::BaseWindow *, bool force); |
843 | + std::vector <Geometry> GetPresentationListGeometries(); |
844 | + |
845 | #ifdef NUX_GESTURES_SUPPORT |
846 | /*! |
847 | Simple wrapper for ProcessEvent for connection with GeisAdapter::event_ready |
848 | @@ -544,6 +576,23 @@ |
849 | std::list<Area *> _queued_layout_list; |
850 | std::vector<Geometry> m_dirty_areas; |
851 | |
852 | + typedef nux::ObjectWeakPtr<nux::BaseWindow> WCWeakBaseWindowPtr; |
853 | + |
854 | + std::vector<WCWeakBaseWindowPtr> m_presentation_list_embedded; |
855 | + |
856 | + /*! |
857 | + This list contains al lthe windows which will be presented on the next frame |
858 | + (eg, after ForeignFrameEnded they are moved into m_presentation_list_embedded |
859 | + and marked for presentation) |
860 | + */ |
861 | + std::vector<WCWeakBaseWindowPtr> m_presentation_list_embedded_next_frame; |
862 | + |
863 | + /*! Whether or not the current frame is "frozen" because the host WM has stopped tracking |
864 | + damage events. If so we should put all presentation requests on the next frame instead |
865 | + of this one |
866 | + */ |
867 | + bool foreign_frame_frozen_; |
868 | + |
869 | //! This variable is true while we are computing the layout the starting from the outmost layout(the Main Layout); |
870 | bool _inside_layout_cycle; |
871 | |
872 | |
873 | === modified file 'NuxGraphics/GLDeviceFrameBufferObject.cpp' |
874 | --- NuxGraphics/GLDeviceFrameBufferObject.cpp 2011-10-19 20:32:38 +0000 |
875 | +++ NuxGraphics/GLDeviceFrameBufferObject.cpp 2013-07-22 17:20:34 +0000 |
876 | @@ -65,12 +65,22 @@ |
877 | |
878 | void GLFramebufferObject::Bind() |
879 | { |
880 | - CHECKGL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fboId)); |
881 | +#ifdef NUX_OPENGLES_20 |
882 | + GLenum binding = GL_FRAMEBUFFER; |
883 | +#else |
884 | + GLenum binding = GL_DRAW_FRAMEBUFFER_EXT; |
885 | +#endif |
886 | + CHECKGL(glBindFramebufferEXT(binding, m_fboId)); |
887 | } |
888 | |
889 | void GLFramebufferObject::Disable() |
890 | { |
891 | - CHECKGL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0)); |
892 | +#ifdef NUX_OPENGLES_20 |
893 | + GLenum binding = GL_FRAMEBUFFER; |
894 | +#else |
895 | + GLenum binding = GL_DRAW_FRAMEBUFFER_EXT; |
896 | +#endif |
897 | + CHECKGL(glBindFramebufferEXT(binding, 0)); |
898 | } |
899 | |
900 | void |
901 | @@ -170,11 +180,11 @@ |
902 | { |
903 | #ifndef NUX_OPENGLES_20 |
904 | // Only binds if m_fboId is different than the currently bound FBO |
905 | - CHECKGL(glGetIntegerv( GL_FRAMEBUFFER_BINDING_EXT, &m_savedFboId )); |
906 | + CHECKGL(glGetIntegerv( GL_DRAW_FRAMEBUFFER_BINDING_EXT, &m_savedFboId )); |
907 | |
908 | if (m_fboId != m_savedFboId) |
909 | { |
910 | - CHECKGL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fboId)); |
911 | + CHECKGL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_fboId)); |
912 | } |
913 | #else |
914 | // Only binds if m_fboId is different than the currently bound FBO |
915 | @@ -189,10 +199,15 @@ |
916 | |
917 | void GLFramebufferObject::_GuardedUnbind() |
918 | { |
919 | +#ifdef NUX_OPENGLES_20 |
920 | + GLenum binding = GL_FRAMEBUFFER; |
921 | +#else |
922 | + GLenum binding = GL_DRAW_FRAMEBUFFER_EXT; |
923 | +#endif |
924 | // Returns FBO binding to the previously enabled FBO |
925 | if (m_savedFboId != m_fboId) |
926 | { |
927 | - CHECKGL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, (GLuint) m_savedFboId)); |
928 | + CHECKGL(glBindFramebufferEXT(binding, (GLuint) m_savedFboId)); |
929 | } |
930 | } |
931 | |
932 | |
933 | === modified file 'NuxGraphics/GpuDevice.cpp' |
934 | --- NuxGraphics/GpuDevice.cpp 2013-05-01 18:12:51 +0000 |
935 | +++ NuxGraphics/GpuDevice.cpp 2013-07-22 17:20:34 +0000 |
936 | @@ -1069,8 +1069,14 @@ |
937 | return; |
938 | } |
939 | |
940 | +#ifdef NUX_OPENGLES_20 |
941 | + GLenum binding = GL_FRAMEBUFFER; |
942 | +#else |
943 | + GLenum binding = GL_DRAW_FRAMEBUFFER_EXT; |
944 | +#endif |
945 | + |
946 | active_framebuffer_object_.Release(); |
947 | - CHECKGL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0)); |
948 | + CHECKGL(glBindFramebufferEXT(binding, 0)); |
949 | CHECKGL(glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0)); |
950 | } |
951 | |
952 | |
953 | === modified file 'NuxGraphics/GpuDeviceTexture.cpp' |
954 | --- NuxGraphics/GpuDeviceTexture.cpp 2012-11-16 19:11:05 +0000 |
955 | +++ NuxGraphics/GpuDeviceTexture.cpp 2013-07-22 17:20:34 +0000 |
956 | @@ -73,7 +73,7 @@ |
957 | return result; |
958 | } |
959 | |
960 | - ObjectPtr<IOpenGLTexture2D> GpuDevice::CreateTexture2DFromID(int /* id */ |
961 | + ObjectPtr<IOpenGLTexture2D> GpuDevice::CreateTexture2DFromID(int id |
962 | , int width |
963 | , int height |
964 | , int levels |
965 | @@ -95,6 +95,12 @@ |
966 | |
967 | ObjectPtr<IOpenGLTexture2D> result; |
968 | result.Adopt(new IOpenGLTexture2D(width, height, levels, pixel_format, true, NUX_FILE_LINE_PARAM)); |
969 | + |
970 | + /* Assign the external id to the internal id. This allows us |
971 | + * to use the foreign texture as if it were a native one. |
972 | + * |
973 | + * This is really important. Don't remove it */ |
974 | + result->_OpenGLID = id; |
975 | return result; |
976 | } |
977 | |
978 | |
979 | === modified file 'NuxGraphics/IOpenGLFrameBufferObject.cpp' |
980 | --- NuxGraphics/IOpenGLFrameBufferObject.cpp 2013-05-01 18:13:16 +0000 |
981 | +++ NuxGraphics/IOpenGLFrameBufferObject.cpp 2013-07-22 17:20:34 +0000 |
982 | @@ -336,7 +336,13 @@ |
983 | // Restore the original opengl back buffer as defined when creating the opengl context(color + depth + stencil). |
984 | int IOpenGLFrameBufferObject::Deactivate() |
985 | { |
986 | - CHECKGL(glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 )); |
987 | +#ifdef NUX_OPENGLES_20 |
988 | + GLenum binding = GL_FRAMEBUFFER; |
989 | +#else |
990 | + GLenum binding = GL_DRAW_FRAMEBUFFER_EXT; |
991 | +#endif |
992 | + |
993 | + CHECKGL(glBindFramebufferEXT( binding, 0 )); |
994 | |
995 | #ifndef NUX_OPENGLES_20 |
996 | CHECKGL(glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0)); |
997 | |
998 | === modified file 'configure.ac' |
999 | --- configure.ac 2013-07-18 15:56:35 +0000 |
1000 | +++ configure.ac 2013-07-22 17:20:34 +0000 |
1001 | @@ -15,7 +15,7 @@ |
1002 | # |
1003 | m4_define([nux_major_version], [4]) |
1004 | m4_define([nux_minor_version], [0]) |
1005 | -m4_define([nux_micro_version], [2]) |
1006 | +m4_define([nux_micro_version], [3]) |
1007 | |
1008 | m4_define([nux_api_version], [4.0]) |
1009 | # Increase the number (to the current date) everytime you propose a branch that breaks the API or ABI |
1010 | @@ -23,8 +23,7 @@ |
1011 | # e.g.: december 5th, 2011 is: 20111205 |
1012 | # To make more than one API change in a day, add a number to the date. Like 20111205.xx |
1013 | |
1014 | -m4_define([nux_abi_version], [20130718.0]) |
1015 | - |
1016 | +m4_define([nux_abi_version], [20130722.0]) |
1017 | m4_define([nux_version], |
1018 | [nux_major_version.nux_minor_version.nux_micro_version]) |
1019 | |
1020 | |
1021 | === modified file 'debian/changelog' |
1022 | --- debian/changelog 2013-07-05 04:02:37 +0000 |
1023 | +++ debian/changelog 2013-07-22 17:20:34 +0000 |
1024 | @@ -1,3 +1,9 @@ |
1025 | +nux (4.0.3+13.10.20130705-0ubuntu2) UNRELEASED; urgency=low |
1026 | + |
1027 | + * Bump ABI |
1028 | + |
1029 | + -- Sam Spilsbury <smspillaz@interpol> Mon, 22 Jul 2013 10:17:41 -0700 |
1030 | + |
1031 | nux (4.0.2+13.10.20130705-0ubuntu1) saucy; urgency=low |
1032 | |
1033 | [ Marco Trevisan (Treviño) ] |
1034 | |
1035 | === modified file 'tests/gtest-nux-windowcompositor.cpp' |
1036 | --- tests/gtest-nux-windowcompositor.cpp 2012-11-19 22:24:05 +0000 |
1037 | +++ tests/gtest-nux-windowcompositor.cpp 2013-07-22 17:20:34 +0000 |
1038 | @@ -53,6 +53,7 @@ |
1039 | TestBaseWindow() : input_area(new nux::InputArea()) |
1040 | { |
1041 | ShowWindow(true); |
1042 | + EnableInputWindow(true); |
1043 | } |
1044 | |
1045 | nux::Area* FindAreaUnderMouse(const nux::Point& /* mouse_position */, nux::NuxEventType /* event_type */) |
1046 | @@ -145,82 +146,147 @@ |
1047 | |
1048 | namespace |
1049 | { |
1050 | + typedef void (*NGLGenFramebuffers)(GLsizei, GLuint *); |
1051 | + typedef void (*NGLGenRenderbuffers)(GLsizei, GLuint *); |
1052 | + typedef void (*NGLBindFramebuffer)(GLenum, GLuint); |
1053 | + typedef void (*NGLBindRenderbuffer)(GLenum, GLuint); |
1054 | + typedef void (*NGLRenderbufferStorage)(GLenum, GLenum, GLsizei, GLsizei); |
1055 | + typedef void (*NGLFramebufferRenderbuffer)(GLenum, GLenum, GLenum, GLuint); |
1056 | + typedef void (*NGLDeleteFramebuffers)(GLsizei, const GLuint *); |
1057 | + typedef void (*NGLDeleteRenderbuffers)(GLsizei, const GLuint *); |
1058 | + |
1059 | + #ifdef NUX_OPENGLES_20 |
1060 | + GLuint NGL_RENDERBUFFER = GL_RENDERBUFFER; |
1061 | + /* No separate draw or read targets on OpenGL|ES */ |
1062 | + GLuint NGL_DRAW_FRAMEBUFFER = GL_FRAMEBUFFER; |
1063 | + GLuint NGL_READ_FRAMEBUFFER = GL_FRAMEBUFFER; |
1064 | + GLuint NGL_DRAW_FRAMEBUFFER_BINDING = GL_FRAMEBUFFER_BINDING; |
1065 | + GLuint NGL_READ_FRAMEBUFFER_BINDING = GL_FRAMEBUFFER_BINDING; |
1066 | + GLuint NGL_COLOR_ATTACHMENT0 = GL_COLOR_ATTACHMENT0; |
1067 | + GLuint NGL_RGBA_STORAGE = GL_RGBA4; |
1068 | + #else |
1069 | + GLuint NGL_RENDERBUFFER = GL_RENDERBUFFER_EXT; |
1070 | + GLuint NGL_DRAW_FRAMEBUFFER = GL_DRAW_FRAMEBUFFER_EXT; |
1071 | + GLuint NGL_READ_FRAMEBUFFER = GL_READ_FRAMEBUFFER_EXT; |
1072 | + GLuint NGL_DRAW_FRAMEBUFFER_BINDING = GL_DRAW_FRAMEBUFFER_BINDING_EXT; |
1073 | + GLuint NGL_READ_FRAMEBUFFER_BINDING = GL_DRAW_FRAMEBUFFER_BINDING_EXT; |
1074 | + GLuint NGL_COLOR_ATTACHMENT0 = GL_COLOR_ATTACHMENT0_EXT; |
1075 | + GLuint NGL_RGBA_STORAGE = GL_RGBA8_EXT; |
1076 | + #endif |
1077 | + |
1078 | class ReferenceFramebuffer |
1079 | { |
1080 | public: |
1081 | |
1082 | ReferenceFramebuffer () |
1083 | { |
1084 | - glGenFramebuffersEXT (1, &fboName); |
1085 | - glGenRenderbuffersEXT (1, &rbName); |
1086 | - |
1087 | - glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, rbName); |
1088 | - glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT, GL_RGBA8_EXT, 300, 200); |
1089 | - glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, fboName); |
1090 | - glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, rbName); |
1091 | + #ifdef NUX_OPENGLES_20 |
1092 | + nglGenFramebuffers = &glGenFramebuffers; |
1093 | + nglGenRenderbuffers = &glGenRenderbuffers; |
1094 | + nglBindRenderbuffer = &glBindRenderbuffer; |
1095 | + nglBindFramebuffer = &glBindFramebuffer; |
1096 | + nglRenderbufferStorage = &glRenderbufferStorage; |
1097 | + nglFramebufferRenderbuffer = &glFramebufferRenderbuffer; |
1098 | + nglDeleteRenderbuffers = &glDeleteRenderbuffers; |
1099 | + nglDeleteFramebuffers = &glDeleteFramebuffers; |
1100 | + #else |
1101 | + nglGenFramebuffers = glGenFramebuffersEXT; |
1102 | + nglGenRenderbuffers = glGenRenderbuffersEXT; |
1103 | + nglBindRenderbuffer = glBindRenderbufferEXT; |
1104 | + nglBindFramebuffer = glBindFramebufferEXT; |
1105 | + nglRenderbufferStorage = glRenderbufferStorageEXT; |
1106 | + nglFramebufferRenderbuffer = glFramebufferRenderbufferEXT; |
1107 | + nglDeleteRenderbuffers = glDeleteRenderbuffersEXT; |
1108 | + nglDeleteFramebuffers = glDeleteFramebuffersEXT; |
1109 | + #endif |
1110 | + |
1111 | + nglGenFramebuffers(1, &fboName); |
1112 | + nglGenRenderbuffers(1, &rbName); |
1113 | + |
1114 | + nglBindRenderbuffer(NGL_RENDERBUFFER, rbName); |
1115 | + nglRenderbufferStorage(NGL_RENDERBUFFER, NGL_RGBA_STORAGE, 300, 200); |
1116 | + nglBindFramebuffer(NGL_DRAW_FRAMEBUFFER, fboName); |
1117 | + nglBindFramebuffer(NGL_READ_FRAMEBUFFER, fboName); |
1118 | + nglFramebufferRenderbuffer(NGL_DRAW_FRAMEBUFFER, NGL_COLOR_ATTACHMENT0, NGL_RENDERBUFFER, rbName); |
1119 | } |
1120 | |
1121 | ~ReferenceFramebuffer () |
1122 | { |
1123 | - glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0); |
1124 | - glDeleteRenderbuffers (1, &rbName); |
1125 | - glDeleteRenderbuffers (1, &fboName); |
1126 | + nglBindFramebuffer(NGL_DRAW_FRAMEBUFFER, 0); |
1127 | + nglBindFramebuffer(NGL_READ_FRAMEBUFFER, 0); |
1128 | + nglDeleteRenderbuffers(1, &rbName); |
1129 | + nglDeleteFramebuffers(1, &fboName); |
1130 | } |
1131 | |
1132 | - GLuint fboName, rbName; |
1133 | + GLuint fboName, rbName; |
1134 | + |
1135 | + /* Each instance of the class needs to keep its own |
1136 | + * copy of the extension functions as glewInit () needs |
1137 | + * to be called in the desktop case before they are available */ |
1138 | + |
1139 | + NGLGenFramebuffers nglGenFramebuffers; |
1140 | + NGLGenRenderbuffers nglGenRenderbuffers; |
1141 | + NGLBindRenderbuffer nglBindRenderbuffer; |
1142 | + NGLBindFramebuffer nglBindFramebuffer; |
1143 | + NGLRenderbufferStorage nglRenderbufferStorage; |
1144 | + NGLFramebufferRenderbuffer nglFramebufferRenderbuffer; |
1145 | + NGLDeleteRenderbuffers nglDeleteRenderbuffers; |
1146 | + NGLDeleteFramebuffers nglDeleteFramebuffers; |
1147 | }; |
1148 | } |
1149 | + |
1150 | TEST_F(TestWindowCompositor, TestRestoreReferenceFramebufferDirect) |
1151 | { |
1152 | ReferenceFramebuffer reference; |
1153 | - GLint fbBinding; |
1154 | - |
1155 | - glGetIntegerv (GL_FRAMEBUFFER_BINDING_EXT, &fbBinding); |
1156 | - |
1157 | - ASSERT_EQ (fbBinding, reference.fboName); |
1158 | - |
1159 | - wnd_thread->GetWindowCompositor().SetReferenceFramebuffer(fbBinding, nux::Geometry (0, 0, 300, 200)); |
1160 | + GLint dfbBinding, rfbBinding; |
1161 | + |
1162 | + glGetIntegerv(NGL_DRAW_FRAMEBUFFER_BINDING, &dfbBinding); |
1163 | + glGetIntegerv(NGL_READ_FRAMEBUFFER_BINDING, &rfbBinding); |
1164 | + |
1165 | + ASSERT_EQ (dfbBinding, reference.fboName); |
1166 | + |
1167 | + wnd_thread->GetWindowCompositor().SetReferenceFramebuffer(dfbBinding, rfbBinding, nux::Geometry (0, 0, 300, 200)); |
1168 | |
1169 | ASSERT_TRUE (wnd_thread->GetWindowCompositor().RestoreReferenceFramebuffer()); |
1170 | - glGetIntegerv (GL_FRAMEBUFFER_BINDING_EXT, &fbBinding); |
1171 | - ASSERT_EQ (fbBinding, reference.fboName); |
1172 | + glGetIntegerv(NGL_DRAW_FRAMEBUFFER_BINDING, &dfbBinding); |
1173 | + glGetIntegerv(NGL_READ_FRAMEBUFFER_BINDING, &rfbBinding); |
1174 | + ASSERT_EQ (dfbBinding, reference.fboName); |
1175 | + ASSERT_EQ (rfbBinding, reference.fboName); |
1176 | } |
1177 | |
1178 | TEST_F(TestWindowCompositor, TestRestoreReferenceFramebufferThroughRestoreMain) |
1179 | { |
1180 | ReferenceFramebuffer reference; |
1181 | - GLint fbBinding; |
1182 | - |
1183 | - glGetIntegerv (GL_FRAMEBUFFER_BINDING_EXT, &fbBinding); |
1184 | - |
1185 | - ASSERT_EQ (fbBinding, reference.fboName); |
1186 | - |
1187 | - wnd_thread->GetWindowCompositor().SetReferenceFramebuffer(fbBinding, nux::Geometry (0, 0, 300, 200)); |
1188 | + GLint dfbBinding, rfbBinding; |
1189 | + |
1190 | + glGetIntegerv(NGL_DRAW_FRAMEBUFFER_BINDING, &dfbBinding); |
1191 | + glGetIntegerv(NGL_READ_FRAMEBUFFER_BINDING, &rfbBinding); |
1192 | + |
1193 | + ASSERT_EQ(dfbBinding, reference.fboName); |
1194 | + |
1195 | + wnd_thread->GetWindowCompositor().SetReferenceFramebuffer(dfbBinding, rfbBinding, nux::Geometry (0, 0, 300, 200)); |
1196 | wnd_thread->GetWindowCompositor().RestoreMainFramebuffer(); |
1197 | - glGetIntegerv (GL_FRAMEBUFFER_BINDING_EXT, &fbBinding); |
1198 | - ASSERT_EQ (fbBinding, reference.fboName); |
1199 | -} |
1200 | - |
1201 | -TEST_F(TestWindowCompositor, TestNoRestoreReferenceFramebufferDirectIfNoReferenceFramebuffer) |
1202 | -{ |
1203 | - GLint fbBinding; |
1204 | - ASSERT_FALSE (wnd_thread->GetWindowCompositor().RestoreReferenceFramebuffer()); |
1205 | - glGetIntegerv (GL_FRAMEBUFFER_BINDING_EXT, &fbBinding); |
1206 | - ASSERT_EQ (fbBinding, 0); |
1207 | + glGetIntegerv(NGL_DRAW_FRAMEBUFFER_BINDING, &dfbBinding); |
1208 | + glGetIntegerv(NGL_READ_FRAMEBUFFER_BINDING, &rfbBinding); |
1209 | + ASSERT_EQ(dfbBinding, reference.fboName); |
1210 | + ASSERT_EQ(rfbBinding, reference.fboName); |
1211 | } |
1212 | |
1213 | TEST_F(TestWindowCompositor, TestRestoreBackbufferThroughRestoreMain) |
1214 | { |
1215 | ReferenceFramebuffer reference; |
1216 | - GLint fbBinding; |
1217 | - |
1218 | - glGetIntegerv (GL_FRAMEBUFFER_BINDING_EXT, &fbBinding); |
1219 | - |
1220 | - ASSERT_EQ (fbBinding, reference.fboName); |
1221 | + GLint dfbBinding, rfbBinding; |
1222 | + |
1223 | + glGetIntegerv(NGL_DRAW_FRAMEBUFFER_BINDING, &dfbBinding); |
1224 | + glGetIntegerv(NGL_READ_FRAMEBUFFER_BINDING, &rfbBinding); |
1225 | + |
1226 | + ASSERT_EQ (dfbBinding, reference.fboName); |
1227 | |
1228 | wnd_thread->GetWindowCompositor().RestoreMainFramebuffer(); |
1229 | - glGetIntegerv (GL_FRAMEBUFFER_BINDING_EXT, &fbBinding); |
1230 | - ASSERT_EQ (fbBinding, 0); |
1231 | + glGetIntegerv(NGL_DRAW_FRAMEBUFFER_BINDING, &dfbBinding); |
1232 | + glGetIntegerv(NGL_READ_FRAMEBUFFER_BINDING, &rfbBinding); |
1233 | + ASSERT_EQ(dfbBinding, 0); |
1234 | + ASSERT_EQ(rfbBinding, 0); |
1235 | } |
1236 | |
1237 | TEST_F(TestWindowCompositor, TestSetKeyFocusArea) |
1238 | |
1239 | === modified file 'tests/gtest-nux-windowthread.cpp' |
1240 | --- tests/gtest-nux-windowthread.cpp 2013-02-01 09:14:07 +0000 |
1241 | +++ tests/gtest-nux-windowthread.cpp 2013-07-22 17:20:34 +0000 |
1242 | @@ -8,17 +8,36 @@ |
1243 | #include <string> |
1244 | #include <fstream> |
1245 | |
1246 | +#include <memory> |
1247 | #include <iostream> |
1248 | #include <gmock/gmock.h> |
1249 | #include <boost/filesystem.hpp> |
1250 | #include <glib.h> |
1251 | |
1252 | +#include <X11/X.h> |
1253 | + |
1254 | #include "Nux/Nux.h" |
1255 | +#include "Nux/View.h" |
1256 | +#include "Nux/HLayout.h" |
1257 | +#include "Nux/ProgramFramework/TestView.h" |
1258 | |
1259 | |
1260 | using namespace testing; |
1261 | using ::testing::Invoke; |
1262 | |
1263 | +namespace nux { |
1264 | + std::ostream & |
1265 | + operator<<(std::ostream &os, const Geometry &geo) |
1266 | + { |
1267 | + return os << "Geometry: x: " << |
1268 | + geo.x << " y: " << |
1269 | + geo.y << " width: " << |
1270 | + geo.width << " height: " << |
1271 | + geo.height << std::endl; |
1272 | + |
1273 | + } |
1274 | +} |
1275 | + |
1276 | namespace { |
1277 | |
1278 | class MockFdDispatch |
1279 | @@ -278,5 +297,482 @@ |
1280 | close (pipefd2[1]); |
1281 | } |
1282 | |
1283 | +class EmbeddedContext : public ::testing::Test |
1284 | +{ |
1285 | + public: |
1286 | + |
1287 | + EmbeddedContext() |
1288 | + : _display(XOpenDisplay(NULL)) |
1289 | + , _root(DefaultRootWindow(_display)) |
1290 | + , _window(XCreateSimpleWindow(_display, |
1291 | + _root, |
1292 | + 0, |
1293 | + 0, |
1294 | + 300, |
1295 | + 200, |
1296 | + 0, |
1297 | + 0, |
1298 | + 0)) |
1299 | + , _visinfo(NULL) |
1300 | + , _context(NULL) |
1301 | + { |
1302 | + XVisualInfo temp; |
1303 | + XWindowAttributes attrib; |
1304 | + if(!XGetWindowAttributes(_display, _window, &attrib)) |
1305 | + throw std::runtime_error("failed to get window attributes"); |
1306 | + |
1307 | + temp.visualid = XVisualIDFromVisual(attrib.visual); |
1308 | + |
1309 | + int nvinfo = 0; |
1310 | + _visinfo = XGetVisualInfo(_display, VisualIDMask, &temp, &nvinfo); |
1311 | + |
1312 | + if (!_visinfo || !nvinfo) |
1313 | + throw std::runtime_error("failed to find visual"); |
1314 | + |
1315 | +#ifndef NUX_OPENGLES_20 |
1316 | + GLint value = 0; |
1317 | + glXGetConfig(_display, _visinfo, GLX_USE_GL, &value); |
1318 | + |
1319 | + if (!value) |
1320 | + std::runtime_error("available visual is not a gl visual"); |
1321 | + |
1322 | + _context = glXCreateContext(_display, _visinfo, NULL, true); |
1323 | + glXMakeCurrent(_display, _window, _context); |
1324 | +#else |
1325 | + EGLDisplay eglDisplay = eglGetDisplay((EGLNativeDisplayType)_display); |
1326 | + EGLint major, minor; |
1327 | + if (!eglInitialize(eglDisplay, &major, &minor)) |
1328 | + throw std::runtime_error("eglInitialize failed"); |
1329 | + |
1330 | + const EGLint config_attribs[] = { |
1331 | + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, |
1332 | + EGL_RED_SIZE, 1, |
1333 | + EGL_GREEN_SIZE, 1, |
1334 | + EGL_BLUE_SIZE, 1, |
1335 | + EGL_ALPHA_SIZE, 0, |
1336 | + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, |
1337 | + EGL_CONFIG_CAVEAT, EGL_NONE, |
1338 | + EGL_STENCIL_SIZE, 1, |
1339 | + EGL_NONE |
1340 | + }; |
1341 | + |
1342 | + const EGLint context_attribs[] = { |
1343 | + EGL_CONTEXT_CLIENT_VERSION, 2, |
1344 | + EGL_NONE |
1345 | + }; |
1346 | + |
1347 | + EGLint count, visualid; |
1348 | + EGLConfig configs[1024]; |
1349 | + |
1350 | + if (!eglChooseConfig(eglDisplay, config_attribs, configs, 1024, &count)) |
1351 | + throw std::runtime_error("eglChooseConfig failed"); |
1352 | + |
1353 | + visualid = temp.visualid; |
1354 | + EGLConfig config = configs[0]; |
1355 | + |
1356 | + for (int i = 0; i < count; ++i) |
1357 | + { |
1358 | + EGLint val; |
1359 | + eglGetConfigAttrib(eglDisplay, configs[i], EGL_NATIVE_VISUAL_ID, &val); |
1360 | + if (visualid == val) |
1361 | + { |
1362 | + config = configs[i]; |
1363 | + break; |
1364 | + } |
1365 | + } |
1366 | + |
1367 | + eglBindAPI(EGL_OPENGL_ES_API); |
1368 | + _surface = eglCreateWindowSurface(eglDisplay, config, _window, 0); |
1369 | + if (_surface == EGL_NO_SURFACE) |
1370 | + throw std::runtime_error("eglCreateWindowSurface failed"); |
1371 | + |
1372 | + _context = eglCreateContext(eglDisplay, config, EGL_NO_CONTEXT, context_attribs); |
1373 | + if (_context == EGL_NO_CONTEXT) |
1374 | + throw std::runtime_error("eglCreateContext failed"); |
1375 | + |
1376 | + if (!eglMakeCurrent(eglDisplay, _surface, _surface, _context)) |
1377 | + throw std::runtime_error("eglMakeCurrent failed"); |
1378 | +#endif |
1379 | + } |
1380 | + |
1381 | + MOCK_METHOD0(verifyInit, void()); |
1382 | + |
1383 | + static void nuxInitThreadEntry(nux::NThread *, void *user_data) |
1384 | + { |
1385 | + EmbeddedContext *context = reinterpret_cast <EmbeddedContext *> (user_data); |
1386 | + context->verifyInit(); |
1387 | + } |
1388 | + |
1389 | + void SetUp () |
1390 | + { |
1391 | + EXPECT_CALL(*this, verifyInit()); |
1392 | + nux::NuxInitialize(0); |
1393 | + _window_thread.reset(nux::CreateFromForeignWindow(_window, |
1394 | + _context, |
1395 | + EmbeddedContext::nuxInitThreadEntry, |
1396 | + this)); |
1397 | + _window_thread->Run(NULL); |
1398 | + while (g_main_context_iteration(g_main_context_default(), false)); |
1399 | + } |
1400 | + |
1401 | + ~EmbeddedContext () |
1402 | + { |
1403 | +#ifndef NUX_OPENGLES_20 |
1404 | + glXDestroyContext(_display, _context); |
1405 | +#else |
1406 | + EGLDisplay eglDisplay = eglGetDisplay((EGLNativeDisplayType)_display); |
1407 | + eglDestroyContext(eglDisplay, _context); |
1408 | + eglDestroySurface(eglDisplay, _surface); |
1409 | + eglTerminate(eglDisplay); |
1410 | +#endif |
1411 | + XDestroyWindow (_display, _window); |
1412 | + XCloseDisplay (_display); |
1413 | + } |
1414 | + |
1415 | + const std::shared_ptr <nux::WindowThread> & |
1416 | + WindowThread () const |
1417 | + { |
1418 | + return _window_thread; |
1419 | + } |
1420 | + |
1421 | + private: |
1422 | + |
1423 | + Display *_display; |
1424 | + Window _root; |
1425 | + Window _window; |
1426 | + XVisualInfo *_visinfo; |
1427 | +#ifndef NUX_OPENGLES_20 |
1428 | + GLXContext _context; |
1429 | +#else |
1430 | + EGLSurface _surface; |
1431 | + EGLContext _context; |
1432 | +#endif |
1433 | + |
1434 | + std::shared_ptr <nux::WindowThread> _window_thread; |
1435 | +}; |
1436 | + |
1437 | +TEST_F(EmbeddedContext, WindowThreadIsEmbedded) |
1438 | +{ |
1439 | + EXPECT_TRUE(WindowThread()->IsEmbeddedWindow()); |
1440 | +} |
1441 | + |
1442 | +/* There's not a whole lot we can do to test this at the moment |
1443 | + * since we can't really mock out the behaviour of GraphicsEngine |
1444 | + */ |
1445 | +TEST_F(EmbeddedContext, PresentViewInEmbeddedReadiesForPresentation) |
1446 | +{ |
1447 | + nux::ObjectPtr <nux::BaseWindow> bw(new nux::BaseWindow(TEXT(""))); |
1448 | + bw->ShowWindow(true, false); |
1449 | + WindowThread()->ForeignFrameEnded(); |
1450 | + bw->PresentInEmbeddedModeOnThisFrame(); |
1451 | + EXPECT_TRUE(bw->AllowPresentationInEmbeddedMode()); |
1452 | +} |
1453 | + |
1454 | +TEST_F(EmbeddedContext, QueueDrawOnChildInEmbeddedReadiesForPresentation) |
1455 | +{ |
1456 | + nux::ObjectPtr <nux::BaseWindow> bw(new nux::BaseWindow(TEXT(""))); |
1457 | + nux::HLayout* layout = new nux::HLayout(NUX_TRACKER_LOCATION); |
1458 | + nux::View* view = new nux::TestView(""); |
1459 | + layout->AddView(view, 1); |
1460 | + bw->SetLayout(layout); |
1461 | + bw->ShowWindow(true, false); |
1462 | + |
1463 | + /* Draw command is implicitly queued by ShowWindow, remove it */ |
1464 | + view->DoneRedraw(); |
1465 | + WindowThread()->ForeignFrameEnded(); |
1466 | + |
1467 | + view->QueueDraw(); |
1468 | + EXPECT_TRUE(bw->AllowPresentationInEmbeddedMode()); |
1469 | +} |
1470 | + |
1471 | +TEST_F(EmbeddedContext, DonePresentViewInEmbeddedMode) |
1472 | +{ |
1473 | + nux::ObjectPtr <nux::BaseWindow> bw(new nux::BaseWindow(TEXT(""))); |
1474 | + bw->PresentInEmbeddedModeOnThisFrame(); |
1475 | + bw->OnPresentedInEmbeddedMode(); |
1476 | + EXPECT_FALSE(bw->AllowPresentationInEmbeddedMode()); |
1477 | +} |
1478 | + |
1479 | +TEST_F(EmbeddedContext, NoPresentInvisibleOnQueueDraw) |
1480 | +{ |
1481 | + nux::ObjectPtr <nux::BaseWindow> window(new nux::BaseWindow(TEXT(""))); |
1482 | + nux::HLayout* layout = new nux::HLayout(NUX_TRACKER_LOCATION); |
1483 | + nux::View* view = new nux::TestView(""); |
1484 | + layout->AddView(view, 1); |
1485 | + window->SetLayout(layout); |
1486 | + window->ShowWindow(false); |
1487 | + view->QueueDraw(); |
1488 | + EXPECT_FALSE(window->AllowPresentationInEmbeddedMode()); |
1489 | +} |
1490 | + |
1491 | +TEST_F(EmbeddedContext, NoPresentInvisible) |
1492 | +{ |
1493 | + nux::ObjectPtr <nux::BaseWindow> window(new nux::BaseWindow(TEXT(""))); |
1494 | + window->ShowWindow(false); |
1495 | + window->PresentInEmbeddedModeOnThisFrame(); |
1496 | + EXPECT_FALSE(window->AllowPresentationInEmbeddedMode()); |
1497 | +} |
1498 | + |
1499 | +TEST_F(EmbeddedContext, AllowPresentationSubsequentQueueDraw) |
1500 | +{ |
1501 | + nux::ObjectPtr <nux::BaseWindow> window(new nux::BaseWindow(TEXT(""))); |
1502 | + nux::HLayout* layout = new nux::HLayout(NUX_TRACKER_LOCATION); |
1503 | + nux::View* view = new nux::TestView(""); |
1504 | + layout->AddView(view, 1); |
1505 | + window->SetLayout(layout); |
1506 | + |
1507 | + /* This will call QueueDraw initially and attempt to add |
1508 | + * the window to the presentation list */ |
1509 | + window->SetGeometry(nux::Geometry(0, 0, 100, 100)); |
1510 | + EXPECT_FALSE(window->AllowPresentationInEmbeddedMode()); |
1511 | + |
1512 | + /* This will call it again */ |
1513 | + window->ShowWindow(true); |
1514 | + EXPECT_TRUE(window->AllowPresentationInEmbeddedMode()); |
1515 | +} |
1516 | + |
1517 | +TEST_F(EmbeddedContext, StillProcessDrawIfInvisible) |
1518 | +{ |
1519 | + nux::ObjectPtr <nux::BaseWindow> window(new nux::BaseWindow(TEXT(""))); |
1520 | + nux::HLayout* layout = new nux::HLayout(NUX_TRACKER_LOCATION); |
1521 | + nux::View* view = new nux::TestView(""); |
1522 | + layout->AddView(view, 1); |
1523 | + window->SetLayout(layout); |
1524 | + window->ShowWindow(false); |
1525 | + view->QueueDraw(); |
1526 | + nux::Geometry clip(0, 0, 100, 100); |
1527 | + WindowThread()->RenderInterfaceFromForeignCmd(&clip); |
1528 | + EXPECT_FALSE(view->IsRedrawNeeded()); |
1529 | +} |
1530 | + |
1531 | +class EmbeddedContextWindow : public EmbeddedContext |
1532 | +{ |
1533 | + public: |
1534 | + |
1535 | + virtual void SetUp() |
1536 | + { |
1537 | + EmbeddedContext::SetUp(); |
1538 | + _base_window = nux::ObjectPtr<nux::BaseWindow>(new nux::BaseWindow(TEXT(""))); |
1539 | + _base_window->ShowWindow(true, false); |
1540 | + |
1541 | + /* QueueDraw will call PresentInEmbeddedModeOnThisFrame - we |
1542 | + * need to unset this state in order to test it properly */ |
1543 | + _base_window->OnPresentedInEmbeddedMode(); |
1544 | + _base_window->DoneRedraw(); |
1545 | + } |
1546 | + |
1547 | + virtual nux::ObjectPtr <nux::BaseWindow> const & |
1548 | + Window() |
1549 | + { |
1550 | + return _base_window; |
1551 | + } |
1552 | + |
1553 | + private: |
1554 | + |
1555 | + nux::ObjectPtr <nux::BaseWindow> _base_window; |
1556 | +}; |
1557 | + |
1558 | +class RedrawRequestVerification |
1559 | +{ |
1560 | + public: |
1561 | + |
1562 | + MOCK_METHOD0(RedrawRequested, void()); |
1563 | +}; |
1564 | + |
1565 | +TEST_F(EmbeddedContextWindow, AllowPresentationRequestsRedraw) |
1566 | +{ |
1567 | + RedrawRequestVerification verification; |
1568 | + |
1569 | + EXPECT_CALL(verification, RedrawRequested()); |
1570 | + WindowThread()->RedrawRequested.connect(sigc::mem_fun (&verification, |
1571 | + &RedrawRequestVerification::RedrawRequested)); |
1572 | + Window()->PresentInEmbeddedModeOnThisFrame(); |
1573 | +} |
1574 | + |
1575 | +TEST_F(EmbeddedContextWindow, AllowPresentationAddsToPresentationList) |
1576 | +{ |
1577 | + Window()->PresentInEmbeddedModeOnThisFrame(); |
1578 | + std::vector <nux::Geometry> present_list(WindowThread()->GetPresentationListGeometries()); |
1579 | + |
1580 | + ASSERT_EQ(1, present_list.size()); |
1581 | + EXPECT_EQ(present_list[0], Window()->GetAbsoluteGeometry()); |
1582 | +} |
1583 | + |
1584 | +TEST_F(EmbeddedContextWindow, MultipleAllowPresentationAddsToPresentationListUnique) |
1585 | +{ |
1586 | + Window()->PresentInEmbeddedModeOnThisFrame(); |
1587 | + Window()->PresentInEmbeddedModeOnThisFrame(); |
1588 | + std::vector <nux::Geometry> present_list(WindowThread()->GetPresentationListGeometries()); |
1589 | + |
1590 | + ASSERT_EQ(1, present_list.size()); |
1591 | + EXPECT_EQ(present_list[0], Window()->GetAbsoluteGeometry()); |
1592 | +} |
1593 | + |
1594 | +TEST_F(EmbeddedContextWindow, OneSetOfGeometryForRePresentOnUnchangedPosition) |
1595 | +{ |
1596 | + Window()->PresentInEmbeddedModeOnThisFrame(); |
1597 | + Window()->OnPresentedInEmbeddedMode(); |
1598 | + Window()->PresentInEmbeddedModeOnThisFrame(); |
1599 | + std::vector <nux::Geometry> present_list(WindowThread()->GetPresentationListGeometries()); |
1600 | + |
1601 | + ASSERT_EQ(1, present_list.size()); |
1602 | + EXPECT_EQ(present_list[0], Window()->GetAbsoluteGeometry()); |
1603 | +} |
1604 | + |
1605 | +TEST_F(EmbeddedContextWindow, TwoSetsOfGeometryForRePresentOnChangedPosition) |
1606 | +{ |
1607 | + Window()->PresentInEmbeddedModeOnThisFrame(); |
1608 | + Window()->OnPresentedInEmbeddedMode(); |
1609 | + Window()->PresentInEmbeddedModeOnThisFrame(); |
1610 | + Window()->SetBaseX(Window()->GetBaseX() + 1); |
1611 | + std::vector <nux::Geometry> present_list(WindowThread()->GetPresentationListGeometries()); |
1612 | + |
1613 | + ASSERT_EQ(2, present_list.size()); |
1614 | + EXPECT_EQ(present_list[0], Window()->GetAbsoluteGeometry()); |
1615 | + EXPECT_EQ(present_list[1], Window()->LastPresentedGeometryInEmbeddedMode()); |
1616 | +} |
1617 | + |
1618 | +TEST_F(EmbeddedContextWindow, QueueDrawAddsParentToPresentationList) |
1619 | +{ |
1620 | + nux::HLayout* layout = new nux::HLayout(NUX_TRACKER_LOCATION); |
1621 | + nux::View* view = new nux::TestView(""); |
1622 | + layout->AddView(view, 1); |
1623 | + Window()->SetLayout(layout); |
1624 | + view->QueueDraw(); |
1625 | + std::vector <nux::Geometry> present_list(WindowThread()->GetPresentationListGeometries()); |
1626 | + |
1627 | + ASSERT_EQ(1, present_list.size()); |
1628 | + EXPECT_EQ(present_list[0], Window()->GetAbsoluteGeometry()); |
1629 | +} |
1630 | + |
1631 | +class EmbeddedContextMultiWindow : public EmbeddedContext |
1632 | +{ |
1633 | + public: |
1634 | + |
1635 | + virtual void SetUp() |
1636 | + { |
1637 | + EmbeddedContext::SetUp(); |
1638 | + } |
1639 | + |
1640 | + const nux::ObjectPtr<nux::BaseWindow> & SpawnWindow() |
1641 | + { |
1642 | + _base_windows.push_back(nux::ObjectPtr<nux::BaseWindow>(new nux::BaseWindow(TEXT("")))); |
1643 | + _base_windows.back()->ShowWindow(true, false); |
1644 | + |
1645 | + /* QueueDraw will call PresentInEmbeddedModeOnThisFrame - we |
1646 | + * need to unset this state in order to test it properly */ |
1647 | + _base_windows.back()->OnPresentedInEmbeddedMode(); |
1648 | + return _base_windows.back(); |
1649 | + } |
1650 | + |
1651 | + virtual std::vector <nux::ObjectPtr <nux::BaseWindow> > const & |
1652 | + Windows() |
1653 | + { |
1654 | + return _base_windows; |
1655 | + } |
1656 | + |
1657 | + private: |
1658 | + |
1659 | + std::vector <nux::ObjectPtr <nux::BaseWindow> > _base_windows; |
1660 | +}; |
1661 | + |
1662 | +TEST_F(EmbeddedContextMultiWindow, PresentIfIntersectsRectOneWindow) |
1663 | +{ |
1664 | + nux::Geometry geo(0, 0, 100, 100); |
1665 | + nux::ObjectPtr<nux::BaseWindow> window(SpawnWindow()); |
1666 | + window->SetGeometry(geo); |
1667 | + WindowThread()->PresentWindowsIntersectingGeometryOnThisFrame(geo); |
1668 | + EXPECT_TRUE(window->AllowPresentationInEmbeddedMode()); |
1669 | +} |
1670 | + |
1671 | +TEST_F(EmbeddedContextMultiWindow, PresentOnlyOneWindow) |
1672 | +{ |
1673 | + nux::Geometry geo(0, 0, 100, 100); |
1674 | + nux::Geometry outside_geo(0, 101, 100, 100); |
1675 | + nux::ObjectPtr<nux::BaseWindow> window(SpawnWindow()); |
1676 | + nux::ObjectPtr<nux::BaseWindow> outside(SpawnWindow()); |
1677 | + window->SetGeometry(geo); |
1678 | + outside->SetGeometry(outside_geo); |
1679 | + |
1680 | + /* Call ForeignFrameEnded to clear the presentation list set up |
1681 | + * by making windows visible */ |
1682 | + WindowThread()->ForeignFrameEnded(); |
1683 | + |
1684 | + WindowThread()->PresentWindowsIntersectingGeometryOnThisFrame(geo); |
1685 | + EXPECT_TRUE(window->AllowPresentationInEmbeddedMode()); |
1686 | + EXPECT_FALSE(outside->AllowPresentationInEmbeddedMode()); |
1687 | +} |
1688 | + |
1689 | +TEST_F(EmbeddedContextMultiWindow, PresentBoth) |
1690 | +{ |
1691 | + nux::Geometry geo(0, 0, 100, 101); |
1692 | + nux::Geometry other_geo(0, 100, 100, 100); |
1693 | + nux::ObjectPtr<nux::BaseWindow> window(SpawnWindow()); |
1694 | + nux::ObjectPtr<nux::BaseWindow> other(SpawnWindow()); |
1695 | + window->SetGeometry(geo); |
1696 | + other->SetGeometry(other_geo); |
1697 | + WindowThread()->PresentWindowsIntersectingGeometryOnThisFrame(geo); |
1698 | + EXPECT_TRUE(window->AllowPresentationInEmbeddedMode()); |
1699 | + EXPECT_TRUE(other->AllowPresentationInEmbeddedMode()); |
1700 | +} |
1701 | + |
1702 | +TEST_F(EmbeddedContextMultiWindow, ForeignFrameEndedPresentNone) |
1703 | +{ |
1704 | + nux::Geometry geo(0, 0, 100, 100); |
1705 | + nux::ObjectPtr<nux::BaseWindow> window(SpawnWindow()); |
1706 | + window->SetGeometry(geo); |
1707 | + WindowThread()->PresentWindowsIntersectingGeometryOnThisFrame(geo); |
1708 | + WindowThread()->ForeignFrameEnded(); |
1709 | + EXPECT_FALSE(window->AllowPresentationInEmbeddedMode()); |
1710 | + EXPECT_TRUE(WindowThread()->GetPresentationListGeometries().empty()); |
1711 | +} |
1712 | + |
1713 | +TEST_F(EmbeddedContextMultiWindow, AddToPresentationListFailsAfterCutoff) |
1714 | +{ |
1715 | + nux::ObjectPtr<nux::BaseWindow> windowOne(SpawnWindow()); |
1716 | + nux::ObjectPtr<nux::BaseWindow> windowTwo(SpawnWindow()); |
1717 | + WindowThread()->ForeignFrameEnded(); |
1718 | + EXPECT_TRUE(WindowThread()->AddToPresentationList(windowOne.GetPointer(), false)); |
1719 | + WindowThread()->ForeignFrameCutoff(); |
1720 | + EXPECT_FALSE(WindowThread()->AddToPresentationList(windowTwo.GetPointer(), false)); |
1721 | +} |
1722 | + |
1723 | +TEST_F(EmbeddedContextMultiWindow, NoPresentInEmbeddedOnThisFrameAfterFrameCutoff) |
1724 | +{ |
1725 | + nux::ObjectPtr<nux::BaseWindow> windowOne(SpawnWindow()); |
1726 | + nux::ObjectPtr<nux::BaseWindow> windowTwo(SpawnWindow()); |
1727 | + WindowThread()->ForeignFrameEnded(); |
1728 | + windowOne->PresentInEmbeddedModeOnThisFrame(); |
1729 | + WindowThread()->ForeignFrameCutoff(); |
1730 | + windowTwo->PresentInEmbeddedModeOnThisFrame(); |
1731 | + EXPECT_TRUE(windowOne->AllowPresentationInEmbeddedMode()); |
1732 | + EXPECT_FALSE(windowTwo->AllowPresentationInEmbeddedMode()); |
1733 | +} |
1734 | + |
1735 | +TEST_F(EmbeddedContextMultiWindow, PresentInEmbeddedOnThisFrameAfterFrameCutoffIfForced) |
1736 | +{ |
1737 | + nux::ObjectPtr<nux::BaseWindow> windowOne(SpawnWindow()); |
1738 | + nux::ObjectPtr<nux::BaseWindow> windowTwo(SpawnWindow()); |
1739 | + WindowThread()->ForeignFrameEnded(); |
1740 | + windowOne->PresentInEmbeddedModeOnThisFrame(); |
1741 | + WindowThread()->ForeignFrameCutoff(); |
1742 | + windowTwo->PresentInEmbeddedModeOnThisFrame(true); |
1743 | + EXPECT_TRUE(windowOne->AllowPresentationInEmbeddedMode()); |
1744 | + EXPECT_TRUE(windowTwo->AllowPresentationInEmbeddedMode()); |
1745 | +} |
1746 | + |
1747 | +TEST_F(EmbeddedContextMultiWindow, MoveToPresentationListAfterFrameEndedIfCaughtInCutoff) |
1748 | +{ |
1749 | + nux::ObjectPtr<nux::BaseWindow> windowOne(SpawnWindow()); |
1750 | + nux::ObjectPtr<nux::BaseWindow> windowTwo(SpawnWindow()); |
1751 | + WindowThread()->ForeignFrameEnded(); |
1752 | + windowOne->PresentInEmbeddedModeOnThisFrame(); |
1753 | + WindowThread()->ForeignFrameCutoff(); |
1754 | + windowTwo->PresentInEmbeddedModeOnThisFrame(); |
1755 | + WindowThread()->ForeignFrameEnded(); |
1756 | + EXPECT_FALSE(windowOne->AllowPresentationInEmbeddedMode()); |
1757 | + EXPECT_TRUE(windowTwo->AllowPresentationInEmbeddedMode()); |
1758 | +} |
1759 | + |
1760 | |
1761 | } |
1762 | |
1763 | === modified file 'tests/gtest-nuxgraphics-texture.cpp' |
1764 | --- tests/gtest-nuxgraphics-texture.cpp 2013-07-03 22:28:18 +0000 |
1765 | +++ tests/gtest-nuxgraphics-texture.cpp 2013-07-22 17:20:34 +0000 |
1766 | @@ -60,6 +60,22 @@ |
1767 | } |
1768 | } |
1769 | |
1770 | +TEST_F(TestTextures, TestCreateTexture2DFromIDAssignemnt) |
1771 | +{ |
1772 | + GLuint texid; |
1773 | + glGenTextures(1, &texid); |
1774 | + glBindTexture(GL_TEXTURE_2D, texid); |
1775 | + nux::ObjectPtr<nux::IOpenGLTexture2D> foreign_texture_as_nux_texture |
1776 | + (nux::GetGraphicsDisplay()->GetGpuDevice()->CreateTexture2DFromID( |
1777 | + texid, |
1778 | + 1, 1, |
1779 | + 0, |
1780 | + nux::BITFMT_B8G8R8A8)); |
1781 | + EXPECT_EQ(texid, foreign_texture_as_nux_texture->GetOpenGLID()); |
1782 | + glBindTexture(GL_TEXTURE_2D, 0); |
1783 | + glDeleteTextures(1, &texid); |
1784 | +} |
1785 | + |
1786 | TEST_F(TestTextures, FallbackTexture2DFromFile) |
1787 | { |
1788 | ASSERT_THAT(CreateTexture2DFromFile(nullptr, -1, false), IsNull()); |
1789 | @@ -102,4 +118,4 @@ |
1790 | ASSERT_THAT(LoadTextureFromFile(std::string()), NotNull()); |
1791 | } |
1792 | |
1793 | -} |
1794 | \ No newline at end of file |
1795 | +} |
39 + void BaseWindow: :WasPresentedIn EmbeddedMode( ) in_embedded_ mode = false; _geometry_ in_embedded_ mode = GetAbsoluteGeom etry();
40 + {
41 + _present_
42 + _last_presented
43 + }
Can we try to find a better name for this function? WasPresented* suggests me that the function should return a bool value.
45 + nux::Geometry const& BaseWindow: :LastPresentedG eometryInEmbedd edMode( ) _geometry_ in_embedded_ mode; :AllowPresentat ionInEmbeddedMo de() in_embedded_ mode;
46 + {
47 + return _last_presented
48 + }
49 +
50 + bool BaseWindow:
51 + {
52 + return _present_
53 + }
Can these methods be const?
+ for (WindowList: :iterator it = _view_window_ list.begin( ); list.end( );
145 + it != _view_window_
146 + ++it)
147 + {
148 + if (it->IsValid())
149 + func (*it);
150 + }
Why not a range-based for loop? :)
206 + void WindowComposito r::SetReference Framebuffer( unsigned int draw_fbo_object,
207 + unsigned int read_fbo_object,
208 + Geometry fbo_geometry)
Geometry const& fbo... ?
374 + WindowComposito r::WeakBaseWind owPtr ptr; compositor_ ->OnAllBaseWind ows(std: :bind(AssignWea kBaseWindowMatc hingRaw, _1, bw, &ptr));
375 + window_
It took me a while to understand what this code was for, maybe we can make it more readable.
406 + for (std::vector< WindowComposito r::WeakBaseWind owPtr>: :iterator it = list_embedded. begin() ; list_embedded. end();
407 + m_presentation_
408 + it != m_presentation_
409 + ++it)
410 + {
For range-based loop... :)
Btw logic looks good to me.