Coverage Report

Created: 2018-09-25 14:53

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