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