1 /* vim:set ts=2 sw=2 sts=2 et: */
2 /* Any copyright is dedicated to the Public Domain.
3 * http://creativecommons.org/publicdomain/zero/1.0/
4 */
5
6 #include "gtest/gtest.h"
7 #include "gmock/gmock.h"
8 #include "TestLayers.h"
9
10 #include "mozilla/gfx/2D.h"
11 #include "mozilla/gfx/Tools.h"
12 #include "mozilla/layers/BufferTexture.h"
13 #include "mozilla/layers/ImageBridgeChild.h" // for ImageBridgeChild
14 #include "mozilla/layers/TextureClient.h"
15 #include "mozilla/layers/TextureHost.h"
16 #include "mozilla/RefPtr.h"
17 #include "gfx2DGlue.h"
18 #include "gfxImageSurface.h"
19 #include "gfxTypes.h"
20 #include "ImageContainer.h"
21 #include "mozilla/layers/ImageDataSerializer.h"
22
23 using namespace mozilla;
24 using namespace mozilla::gfx;
25 using namespace mozilla::layers;
26
27 /*
28 * This test performs the following actions:
29 * - creates a surface
30 * - initialize a texture client with it
31 * - serilaizes the texture client
32 * - deserializes the data into a texture host
33 * - reads the surface from the texture host.
34 *
35 * The surface in the end should be equal to the inital one.
36 * This test is run for different combinations of texture types and
37 * image formats.
38 */
39
40 namespace mozilla {
41 namespace layers {
42
43 // fills the surface with values betwee 0 and 100.
SetupSurface(gfxImageSurface * surface)44 void SetupSurface(gfxImageSurface* surface) {
45 int bpp = gfxASurface::BytePerPixelFromFormat(surface->Format());
46 int stride = surface->Stride();
47 uint8_t val = 0;
48 uint8_t* data = surface->Data();
49 for (int y = 0; y < surface->Height(); ++y) {
50 for (int x = 0; x < surface->Height(); ++x) {
51 for (int b = 0; b < bpp; ++b) {
52 data[y*stride + x*bpp + b] = val;
53 if (val == 100) {
54 val = 0;
55 } else {
56 ++val;
57 }
58 }
59 }
60 }
61 }
62
63 // return true if two surfaces contain the same data
AssertSurfacesEqual(gfxImageSurface * surface1,gfxImageSurface * surface2)64 void AssertSurfacesEqual(gfxImageSurface* surface1,
65 gfxImageSurface* surface2)
66 {
67 ASSERT_EQ(surface1->GetSize(), surface2->GetSize());
68 ASSERT_EQ(surface1->Format(), surface2->Format());
69
70 uint8_t* data1 = surface1->Data();
71 uint8_t* data2 = surface2->Data();
72 int stride1 = surface1->Stride();
73 int stride2 = surface2->Stride();
74 int bpp = gfxASurface::BytePerPixelFromFormat(surface1->Format());
75
76 for (int y = 0; y < surface1->Height(); ++y) {
77 for (int x = 0; x < surface1->Width(); ++x) {
78 for (int b = 0; b < bpp; ++b) {
79 ASSERT_EQ(data1[y*stride1 + x*bpp + b],
80 data2[y*stride2 + x*bpp + b]);
81 }
82 }
83 }
84 }
85
AssertSurfacesEqual(SourceSurface * surface1,SourceSurface * surface2)86 void AssertSurfacesEqual(SourceSurface* surface1,
87 SourceSurface* surface2)
88 {
89 ASSERT_EQ(surface1->GetSize(), surface2->GetSize());
90 ASSERT_EQ(surface1->GetFormat(), surface2->GetFormat());
91
92 RefPtr<DataSourceSurface> dataSurface1 = surface1->GetDataSurface();
93 RefPtr<DataSourceSurface> dataSurface2 = surface2->GetDataSurface();
94 DataSourceSurface::MappedSurface map1;
95 DataSourceSurface::MappedSurface map2;
96 if (!dataSurface1->Map(DataSourceSurface::READ, &map1)) {
97 return;
98 }
99 if (!dataSurface2->Map(DataSourceSurface::READ, &map2)) {
100 dataSurface1->Unmap();
101 return;
102 }
103 uint8_t* data1 = map1.mData;
104 uint8_t* data2 = map2.mData;
105 int stride1 = map1.mStride;
106 int stride2 = map2.mStride;
107 int bpp = BytesPerPixel(surface1->GetFormat());
108 int width = surface1->GetSize().width;
109 int height = surface1->GetSize().height;
110
111 for (int y = 0; y < height; ++y) {
112 for (int x = 0; x < width; ++x) {
113 for (int b = 0; b < bpp; ++b) {
114 ASSERT_EQ(data1[y*stride1 + x*bpp + b],
115 data2[y*stride2 + x*bpp + b]);
116 }
117 }
118 }
119
120 dataSurface1->Unmap();
121 dataSurface2->Unmap();
122 }
123
124 // Run the test for a texture client and a surface
TestTextureClientSurface(TextureClient * texture,gfxImageSurface * surface)125 void TestTextureClientSurface(TextureClient* texture, gfxImageSurface* surface) {
126
127 // client allocation
128 ASSERT_TRUE(texture->CanExposeDrawTarget());
129
130 ASSERT_TRUE(texture->Lock(OpenMode::OPEN_READ_WRITE));
131 // client painting
132 RefPtr<DrawTarget> dt = texture->BorrowDrawTarget();
133 RefPtr<SourceSurface> source =
134 gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(dt, surface);
135 dt->CopySurface(source, IntRect(IntPoint(), source->GetSize()), IntPoint());
136
137 RefPtr<SourceSurface> snapshot = dt->Snapshot();
138
139 AssertSurfacesEqual(snapshot, source);
140
141 dt = nullptr; // drop reference before calling Unlock()
142 texture->Unlock();
143
144 // client serialization
145 SurfaceDescriptor descriptor;
146 ASSERT_TRUE(texture->ToSurfaceDescriptor(descriptor));
147
148 ASSERT_NE(descriptor.type(), SurfaceDescriptor::Tnull_t);
149
150 // host deserialization
151 RefPtr<TestSurfaceAllocator> deallocator = new TestSurfaceAllocator();
152 RefPtr<TextureHost> host = CreateBackendIndependentTextureHost(descriptor, deallocator,
153 texture->GetFlags());
154
155 ASSERT_TRUE(host.get() != nullptr);
156 ASSERT_EQ(host->GetFlags(), texture->GetFlags());
157
158 // host read
159
160 // XXX - this can fail because lock tries to upload the texture but it needs a
161 // Compositor to do that. We could add a DummyComposior for testing but I am
162 // not sure it'll be worth it. Maybe always test against a BasicCompositor,
163 // but the latter needs a widget...
164 if (host->Lock()) {
165 RefPtr<mozilla::gfx::DataSourceSurface> hostDataSurface = host->GetAsSurface();
166
167 RefPtr<gfxImageSurface> hostSurface =
168 new gfxImageSurface(hostDataSurface->GetData(),
169 hostDataSurface->GetSize(),
170 hostDataSurface->Stride(),
171 SurfaceFormatToImageFormat(hostDataSurface->GetFormat()));
172 AssertSurfacesEqual(surface, hostSurface.get());
173 host->Unlock();
174 }
175 }
176
177 // Same as above, for YCbCr surfaces
TestTextureClientYCbCr(TextureClient * client,PlanarYCbCrData & ycbcrData)178 void TestTextureClientYCbCr(TextureClient* client, PlanarYCbCrData& ycbcrData) {
179 client->Lock(OpenMode::OPEN_READ_WRITE);
180 UpdateYCbCrTextureClient(client, ycbcrData);
181 client->Unlock();
182
183 // client serialization
184 SurfaceDescriptor descriptor;
185 ASSERT_TRUE(client->ToSurfaceDescriptor(descriptor));
186
187 ASSERT_EQ(descriptor.type(), SurfaceDescriptor::TSurfaceDescriptorBuffer);
188 auto bufferDesc = descriptor.get_SurfaceDescriptorBuffer();
189 ASSERT_EQ(bufferDesc.desc().type(), BufferDescriptor::TYCbCrDescriptor);
190 auto ycbcrDesc = bufferDesc.desc().get_YCbCrDescriptor();
191 ASSERT_EQ(ycbcrDesc.ySize(), ycbcrData.mYSize);
192 ASSERT_EQ(ycbcrDesc.cbCrSize(), ycbcrData.mCbCrSize);
193 ASSERT_EQ(ycbcrDesc.stereoMode(), ycbcrData.mStereoMode);
194
195 // host deserialization
196 RefPtr<TestSurfaceAllocator> deallocator = new TestSurfaceAllocator();
197 RefPtr<TextureHost> textureHost = CreateBackendIndependentTextureHost(descriptor, deallocator,
198 client->GetFlags());
199
200 RefPtr<BufferTextureHost> host = static_cast<BufferTextureHost*>(textureHost.get());
201
202 ASSERT_TRUE(host.get() != nullptr);
203 ASSERT_EQ(host->GetFlags(), client->GetFlags());
204
205 // host read
206
207 if (host->Lock()) {
208 // This will work iff the compositor is not BasicCompositor
209 ASSERT_EQ(host->GetFormat(), mozilla::gfx::SurfaceFormat::YUV);
210 host->Unlock();
211 }
212 }
213
214 } // namespace layers
215 } // namespace mozilla
216
TEST(Layers,TextureSerialization)217 TEST(Layers, TextureSerialization) {
218 // the test is run on all the following image formats
219 gfxImageFormat formats[3] = {
220 SurfaceFormat::A8R8G8B8_UINT32,
221 SurfaceFormat::X8R8G8B8_UINT32,
222 SurfaceFormat::A8,
223 };
224
225 for (int f = 0; f < 3; ++f) {
226 RefPtr<gfxImageSurface> surface = new gfxImageSurface(IntSize(400,300), formats[f]);
227 SetupSurface(surface.get());
228 AssertSurfacesEqual(surface, surface);
229
230 auto texData = BufferTextureData::Create(surface->GetSize(),
231 gfx::ImageFormatToSurfaceFormat(surface->Format()),
232 gfx::BackendType::CAIRO, LayersBackend::LAYERS_NONE,
233 TextureFlags::DEALLOCATE_CLIENT, ALLOC_DEFAULT, nullptr
234 );
235 ASSERT_TRUE(!!texData);
236
237 RefPtr<TextureClient> client = new TextureClient(
238 texData, TextureFlags::DEALLOCATE_CLIENT, nullptr
239 );
240
241 TestTextureClientSurface(client, surface);
242
243 // XXX - Test more texture client types.
244 }
245 }
246
TEST(Layers,TextureYCbCrSerialization)247 TEST(Layers, TextureYCbCrSerialization) {
248 RefPtr<gfxImageSurface> ySurface = new gfxImageSurface(IntSize(400,300), SurfaceFormat::A8);
249 RefPtr<gfxImageSurface> cbSurface = new gfxImageSurface(IntSize(200,150), SurfaceFormat::A8);
250 RefPtr<gfxImageSurface> crSurface = new gfxImageSurface(IntSize(200,150), SurfaceFormat::A8);
251 SetupSurface(ySurface.get());
252 SetupSurface(cbSurface.get());
253 SetupSurface(crSurface.get());
254
255 PlanarYCbCrData clientData;
256 clientData.mYChannel = ySurface->Data();
257 clientData.mCbChannel = cbSurface->Data();
258 clientData.mCrChannel = crSurface->Data();
259 clientData.mYSize = ySurface->GetSize();
260 clientData.mPicSize = ySurface->GetSize();
261 clientData.mCbCrSize = cbSurface->GetSize();
262 clientData.mYStride = ySurface->Stride();
263 clientData.mCbCrStride = cbSurface->Stride();
264 clientData.mStereoMode = StereoMode::MONO;
265 clientData.mYUVColorSpace = YUVColorSpace::BT601;
266 clientData.mYSkip = 0;
267 clientData.mCbSkip = 0;
268 clientData.mCrSkip = 0;
269 clientData.mCrSkip = 0;
270 clientData.mPicX = 0;
271 clientData.mPicX = 0;
272
273 ImageBridgeChild::InitSameProcess();
274
275 RefPtr<ImageBridgeChild> imageBridge = ImageBridgeChild::GetSingleton();
276 static int retry = 5;
277 while(!imageBridge->IPCOpen() && retry) {
278 // IPDL connection takes time especially in slow testing environment, like
279 // VM machines. Here we added retry mechanism to wait for IPDL connnection.
280 #ifdef XP_WIN
281 Sleep(1);
282 #else
283 sleep(1);
284 #endif
285 retry--;
286 }
287
288 // Skip this testing if IPDL connection is not ready
289 if (!retry && !imageBridge->IPCOpen()) {
290 return;
291 }
292
293 RefPtr<TextureClient> client = TextureClient::CreateForYCbCr(imageBridge, clientData.mYSize, clientData.mCbCrSize,
294 StereoMode::MONO, YUVColorSpace::BT601,
295 TextureFlags::DEALLOCATE_CLIENT);
296
297 TestTextureClientYCbCr(client, clientData);
298
299 // XXX - Test more texture client types.
300 }
301