|
1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- |
|
2 * This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 #include "SimpleTextureClientPool.h" |
|
7 #include "CompositableClient.h" |
|
8 #include "mozilla/layers/ISurfaceAllocator.h" |
|
9 |
|
10 #include "gfxPrefs.h" |
|
11 |
|
12 #include "nsComponentManagerUtils.h" |
|
13 |
|
14 #if 0 |
|
15 #define RECYCLE_LOG(...) printf_stderr(__VA_ARGS__) |
|
16 #else |
|
17 #define RECYCLE_LOG(...) do { } while (0) |
|
18 #endif |
|
19 |
|
20 namespace mozilla { |
|
21 namespace layers { |
|
22 |
|
23 using gfx::SurfaceFormat; |
|
24 |
|
25 /* static */ void |
|
26 SimpleTextureClientPool::ShrinkCallback(nsITimer *aTimer, void *aClosure) |
|
27 { |
|
28 static_cast<SimpleTextureClientPool*>(aClosure)->ShrinkToMinimumSize(); |
|
29 } |
|
30 |
|
31 /* static */ void |
|
32 SimpleTextureClientPool::RecycleCallback(TextureClient* aClient, void* aClosure) |
|
33 { |
|
34 SimpleTextureClientPool* pool = |
|
35 static_cast<SimpleTextureClientPool*>(aClosure); |
|
36 |
|
37 aClient->ClearRecycleCallback(); |
|
38 pool->ReturnTextureClient(aClient); |
|
39 } |
|
40 |
|
41 /* static */ void |
|
42 SimpleTextureClientPool::WaitForCompositorRecycleCallback(TextureClient* aClient, void* aClosure) |
|
43 { |
|
44 // This will grab a reference that will be released once the compositor |
|
45 // acknowledges the remote recycle. Once it is received the object |
|
46 // will be fully recycled. |
|
47 aClient->WaitForCompositorRecycle(); |
|
48 aClient->SetRecycleCallback(SimpleTextureClientPool::RecycleCallback, aClosure); |
|
49 } |
|
50 |
|
51 SimpleTextureClientPool::SimpleTextureClientPool(gfx::SurfaceFormat aFormat, gfx::IntSize aSize, |
|
52 ISurfaceAllocator *aAllocator) |
|
53 : mFormat(aFormat) |
|
54 , mSize(aSize) |
|
55 , mSurfaceAllocator(aAllocator) |
|
56 { |
|
57 mTimer = do_CreateInstance("@mozilla.org/timer;1"); |
|
58 } |
|
59 |
|
60 TemporaryRef<TextureClient> |
|
61 SimpleTextureClientPool::GetTextureClient(bool aAutoRecycle) |
|
62 { |
|
63 // Try to fetch a client from the pool |
|
64 RefPtr<TextureClient> textureClient; |
|
65 if (mAvailableTextureClients.size()) { |
|
66 textureClient = mAvailableTextureClients.top(); |
|
67 textureClient->WaitReleaseFence(); |
|
68 mAvailableTextureClients.pop(); |
|
69 RECYCLE_LOG("%s Skip allocate (%i left), returning %p\n", (mFormat == SurfaceFormat::B8G8R8A8?"poolA":"poolX"), mAvailableTextureClients.size(), textureClient.get()); |
|
70 |
|
71 } else { |
|
72 // No unused clients in the pool, create one |
|
73 if (gfxPrefs::ForceShmemTiles()) { |
|
74 textureClient = TextureClient::CreateBufferTextureClient(mSurfaceAllocator, |
|
75 mFormat, TEXTURE_IMMEDIATE_UPLOAD | TEXTURE_RECYCLE, gfx::BackendType::NONE); |
|
76 } else { |
|
77 textureClient = TextureClient::CreateTextureClientForDrawing(mSurfaceAllocator, |
|
78 mFormat, TEXTURE_FLAGS_DEFAULT | TEXTURE_RECYCLE, gfx::BackendType::NONE, mSize); |
|
79 } |
|
80 if (!textureClient->AllocateForSurface(mSize, ALLOC_DEFAULT)) { |
|
81 NS_WARNING("TextureClient::AllocateForSurface failed!"); |
|
82 } |
|
83 RECYCLE_LOG("%s Must allocate (0 left), returning %p\n", (mFormat == SurfaceFormat::B8G8R8A8?"poolA":"poolX"), textureClient.get()); |
|
84 } |
|
85 |
|
86 if (aAutoRecycle) { |
|
87 mOutstandingTextureClients.push_back(textureClient); |
|
88 textureClient->SetRecycleCallback(SimpleTextureClientPool::WaitForCompositorRecycleCallback, this); |
|
89 } |
|
90 |
|
91 return textureClient; |
|
92 } |
|
93 |
|
94 void |
|
95 SimpleTextureClientPool::ReturnTextureClient(TextureClient *aClient) |
|
96 { |
|
97 if (!aClient) { |
|
98 return; |
|
99 } |
|
100 |
|
101 // If we haven't hit our max cached client limit, add this one |
|
102 if (mAvailableTextureClients.size() < sMaxTextureClients) { |
|
103 mAvailableTextureClients.push(aClient); |
|
104 RECYCLE_LOG("%s recycled %p (have %d)\n", (mFormat == SurfaceFormat::B8G8R8A8?"poolA":"poolX"), aClient, mAvailableTextureClients.size()); |
|
105 } else { |
|
106 RECYCLE_LOG("%s did not recycle %p (have %d)\n", (mFormat == SurfaceFormat::B8G8R8A8?"poolA":"poolX"), aClient, mAvailableTextureClients.size()); |
|
107 } |
|
108 |
|
109 // Kick off the pool shrinking timer if there are still more unused texture |
|
110 // clients than our desired minimum cache size. |
|
111 if (mAvailableTextureClients.size() > sMinCacheSize) { |
|
112 mTimer->InitWithFuncCallback(SimpleTextureClientPool::ShrinkCallback, this, sShrinkTimeout, |
|
113 nsITimer::TYPE_ONE_SHOT); |
|
114 } |
|
115 |
|
116 mOutstandingTextureClients.remove(aClient); |
|
117 } |
|
118 |
|
119 void |
|
120 SimpleTextureClientPool::ShrinkToMinimumSize() |
|
121 { |
|
122 RECYCLE_LOG("%s ShrinkToMinimumSize, removing %d clients", (mFormat == SurfaceFormat::B8G8R8A8?"poolA":"poolX"), mAvailableTextureClients.size() > sMinCacheSize ? mAvailableTextureClients.size() - sMinCacheSize : 0); |
|
123 |
|
124 mTimer->Cancel(); |
|
125 |
|
126 while (mAvailableTextureClients.size() > sMinCacheSize) { |
|
127 mAvailableTextureClients.pop(); |
|
128 } |
|
129 } |
|
130 |
|
131 void |
|
132 SimpleTextureClientPool::Clear() |
|
133 { |
|
134 while (!mAvailableTextureClients.empty()) { |
|
135 mAvailableTextureClients.pop(); |
|
136 } |
|
137 } |
|
138 |
|
139 } |
|
140 } |