1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/tests/gtest/TestTextures.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,315 @@ 1.4 +/* vim:set ts=2 sw=2 sts=2 et: */ 1.5 +/* Any copyright is dedicated to the Public Domain. 1.6 + * http://creativecommons.org/publicdomain/zero/1.0/ 1.7 + */ 1.8 + 1.9 +#include "gtest/gtest.h" 1.10 +#include "gmock/gmock.h" 1.11 + 1.12 +#include "mozilla/gfx/2D.h" 1.13 +#include "mozilla/gfx/Tools.h" 1.14 +#include "mozilla/layers/TextureClient.h" 1.15 +#include "mozilla/layers/TextureHost.h" 1.16 +#include "mozilla/RefPtr.h" 1.17 +#include "gfx2DGlue.h" 1.18 +#include "gfxImageSurface.h" 1.19 +#include "gfxTypes.h" 1.20 +#include "ImageContainer.h" 1.21 +#include "mozilla/layers/YCbCrImageDataSerializer.h" 1.22 + 1.23 +using namespace mozilla; 1.24 +using namespace mozilla::gfx; 1.25 +using namespace mozilla::layers; 1.26 + 1.27 +/* 1.28 + * This test performs the following actions: 1.29 + * - creates a surface 1.30 + * - initialize a texture client with it 1.31 + * - serilaizes the texture client 1.32 + * - deserializes the data into a texture host 1.33 + * - reads the surface from the texture host. 1.34 + * 1.35 + * The surface in the end should be equal to the inital one. 1.36 + * This test is run for different combinations of texture types and 1.37 + * image formats. 1.38 + */ 1.39 + 1.40 +namespace mozilla { 1.41 +namespace layers { 1.42 + 1.43 +// fills the surface with values betwee 0 and 100. 1.44 +void SetupSurface(gfxImageSurface* surface) { 1.45 + int bpp = gfxASurface::BytePerPixelFromFormat(surface->Format()); 1.46 + int stride = surface->Stride(); 1.47 + uint8_t val = 0; 1.48 + uint8_t* data = surface->Data(); 1.49 + for (int y = 0; y < surface->Height(); ++y) { 1.50 + for (int x = 0; x < surface->Height(); ++x) { 1.51 + for (int b = 0; b < bpp; ++b) { 1.52 + data[y*stride + x*bpp + b] = val; 1.53 + if (val == 100) { 1.54 + val = 0; 1.55 + } else { 1.56 + ++val; 1.57 + } 1.58 + } 1.59 + } 1.60 + } 1.61 +} 1.62 + 1.63 +// return true if two surfaces contain the same data 1.64 +void AssertSurfacesEqual(gfxImageSurface* surface1, 1.65 + gfxImageSurface* surface2) 1.66 +{ 1.67 + ASSERT_EQ(surface1->GetSize(), surface2->GetSize()); 1.68 + ASSERT_EQ(surface1->Format(), surface2->Format()); 1.69 + 1.70 + uint8_t* data1 = surface1->Data(); 1.71 + uint8_t* data2 = surface2->Data(); 1.72 + int stride1 = surface1->Stride(); 1.73 + int stride2 = surface2->Stride(); 1.74 + int bpp = gfxASurface::BytePerPixelFromFormat(surface1->Format()); 1.75 + 1.76 + for (int y = 0; y < surface1->Height(); ++y) { 1.77 + for (int x = 0; x < surface1->Width(); ++x) { 1.78 + for (int b = 0; b < bpp; ++b) { 1.79 + ASSERT_EQ(data1[y*stride1 + x*bpp + b], 1.80 + data2[y*stride2 + x*bpp + b]); 1.81 + } 1.82 + } 1.83 + } 1.84 +} 1.85 + 1.86 +void AssertSurfacesEqual(SourceSurface* surface1, 1.87 + SourceSurface* surface2) 1.88 +{ 1.89 + ASSERT_EQ(surface1->GetSize(), surface2->GetSize()); 1.90 + ASSERT_EQ(surface1->GetFormat(), surface2->GetFormat()); 1.91 + 1.92 + RefPtr<DataSourceSurface> dataSurface1 = surface1->GetDataSurface(); 1.93 + RefPtr<DataSourceSurface> dataSurface2 = surface2->GetDataSurface(); 1.94 + DataSourceSurface::MappedSurface map1; 1.95 + DataSourceSurface::MappedSurface map2; 1.96 + if (!dataSurface1->Map(DataSourceSurface::READ, &map1)) { 1.97 + return; 1.98 + } 1.99 + if (!dataSurface2->Map(DataSourceSurface::READ, &map2)) { 1.100 + dataSurface1->Unmap(); 1.101 + return; 1.102 + } 1.103 + uint8_t* data1 = map1.mData; 1.104 + uint8_t* data2 = map2.mData; 1.105 + int stride1 = map1.mStride; 1.106 + int stride2 = map2.mStride; 1.107 + int bpp = BytesPerPixel(surface1->GetFormat()); 1.108 + int width = surface1->GetSize().width; 1.109 + int height = surface1->GetSize().height; 1.110 + 1.111 + for (int y = 0; y < height; ++y) { 1.112 + for (int x = 0; x < width; ++x) { 1.113 + for (int b = 0; b < bpp; ++b) { 1.114 + ASSERT_EQ(data1[y*stride1 + x*bpp + b], 1.115 + data2[y*stride2 + x*bpp + b]); 1.116 + } 1.117 + } 1.118 + } 1.119 + 1.120 + dataSurface1->Unmap(); 1.121 + dataSurface2->Unmap(); 1.122 +} 1.123 + 1.124 +// Same as above, for YCbCr surfaces 1.125 +void AssertYCbCrSurfacesEqual(PlanarYCbCrData* surface1, 1.126 + PlanarYCbCrData* surface2) 1.127 +{ 1.128 + ASSERT_EQ(surface1->mYSize, surface2->mYSize); 1.129 + ASSERT_EQ(surface1->mCbCrSize, surface2->mCbCrSize); 1.130 + ASSERT_EQ(surface1->mStereoMode, surface2->mStereoMode); 1.131 + ASSERT_EQ(surface1->mPicSize, surface2->mPicSize); 1.132 + 1.133 + for (int y = 0; y < surface1->mYSize.height; ++y) { 1.134 + for (int x = 0; x < surface1->mYSize.width; ++x) { 1.135 + ASSERT_EQ(surface1->mYChannel[y*surface1->mYStride + x*(1+surface1->mYSkip)], 1.136 + surface2->mYChannel[y*surface2->mYStride + x*(1+surface2->mYSkip)]); 1.137 + } 1.138 + } 1.139 + for (int y = 0; y < surface1->mCbCrSize.height; ++y) { 1.140 + for (int x = 0; x < surface1->mCbCrSize.width; ++x) { 1.141 + ASSERT_EQ(surface1->mCbChannel[y*surface1->mCbCrStride + x*(1+surface1->mCbSkip)], 1.142 + surface2->mCbChannel[y*surface2->mCbCrStride + x*(1+surface2->mCbSkip)]); 1.143 + ASSERT_EQ(surface1->mCrChannel[y*surface1->mCbCrStride + x*(1+surface1->mCrSkip)], 1.144 + surface2->mCrChannel[y*surface2->mCbCrStride + x*(1+surface2->mCrSkip)]); 1.145 + } 1.146 + } 1.147 +} 1.148 + 1.149 +// Run the test for a texture client and a surface 1.150 +void TestTextureClientSurface(TextureClient* texture, gfxImageSurface* surface) { 1.151 + 1.152 + // client allocation 1.153 + ASSERT_TRUE(texture->CanExposeDrawTarget()); 1.154 + texture->AllocateForSurface(ToIntSize(surface->GetSize())); 1.155 + ASSERT_TRUE(texture->IsAllocated()); 1.156 + 1.157 + ASSERT_TRUE(texture->Lock(OPEN_READ_WRITE)); 1.158 + // client painting 1.159 + RefPtr<DrawTarget> dt = texture->GetAsDrawTarget(); 1.160 + RefPtr<SourceSurface> source = 1.161 + gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(dt, surface); 1.162 + dt->CopySurface(source, IntRect(IntPoint(), source->GetSize()), IntPoint()); 1.163 + 1.164 + RefPtr<SourceSurface> snapshot = dt->Snapshot(); 1.165 + 1.166 + AssertSurfacesEqual(snapshot, source); 1.167 + 1.168 + dt = nullptr; // drop reference before calling Unlock() 1.169 + texture->Unlock(); 1.170 + 1.171 + // client serialization 1.172 + SurfaceDescriptor descriptor; 1.173 + ASSERT_TRUE(texture->ToSurfaceDescriptor(descriptor)); 1.174 + 1.175 + ASSERT_NE(descriptor.type(), SurfaceDescriptor::Tnull_t); 1.176 + 1.177 + // host deserialization 1.178 + RefPtr<TextureHost> host = CreateBackendIndependentTextureHost(descriptor, nullptr, 1.179 + texture->GetFlags()); 1.180 + 1.181 + ASSERT_TRUE(host.get() != nullptr); 1.182 + ASSERT_EQ(host->GetFlags(), texture->GetFlags()); 1.183 + 1.184 + // host read 1.185 + ASSERT_TRUE(host->Lock()); 1.186 + RefPtr<mozilla::gfx::DataSourceSurface> hostDataSurface = host->GetAsSurface(); 1.187 + host->Unlock(); 1.188 + 1.189 + nsRefPtr<gfxImageSurface> hostSurface = 1.190 + new gfxImageSurface(hostDataSurface->GetData(), 1.191 + ThebesIntSize(hostDataSurface->GetSize()), 1.192 + hostDataSurface->Stride(), 1.193 + SurfaceFormatToImageFormat(hostDataSurface->GetFormat())); 1.194 + AssertSurfacesEqual(surface, hostSurface.get()); 1.195 +} 1.196 + 1.197 +// Same as above, for YCbCr surfaces 1.198 +void TestTextureClientYCbCr(TextureClient* client, PlanarYCbCrData& ycbcrData) { 1.199 + 1.200 + // client allocation 1.201 + ASSERT_TRUE(client->AsTextureClientYCbCr() != nullptr); 1.202 + TextureClientYCbCr* texture = client->AsTextureClientYCbCr(); 1.203 + texture->AllocateForYCbCr(ycbcrData.mYSize, 1.204 + ycbcrData.mCbCrSize, 1.205 + ycbcrData.mStereoMode); 1.206 + ASSERT_TRUE(client->IsAllocated()); 1.207 + 1.208 + ASSERT_TRUE(client->Lock(OPEN_READ_WRITE)); 1.209 + // client painting 1.210 + texture->UpdateYCbCr(ycbcrData); 1.211 + client->Unlock(); 1.212 + 1.213 + // client serialization 1.214 + SurfaceDescriptor descriptor; 1.215 + ASSERT_TRUE(client->ToSurfaceDescriptor(descriptor)); 1.216 + 1.217 + ASSERT_NE(descriptor.type(), SurfaceDescriptor::Tnull_t); 1.218 + 1.219 + // host deserialization 1.220 + RefPtr<TextureHost> textureHost = CreateBackendIndependentTextureHost(descriptor, nullptr, 1.221 + client->GetFlags()); 1.222 + 1.223 + RefPtr<BufferTextureHost> host = static_cast<BufferTextureHost*>(textureHost.get()); 1.224 + 1.225 + ASSERT_TRUE(host.get() != nullptr); 1.226 + ASSERT_EQ(host->GetFlags(), client->GetFlags()); 1.227 + 1.228 + // host read 1.229 + ASSERT_TRUE(host->Lock()); 1.230 + 1.231 + // This will work iff the compositor is not BasicCompositor 1.232 + ASSERT_EQ(host->GetFormat(), mozilla::gfx::SurfaceFormat::YUV); 1.233 + 1.234 + YCbCrImageDataDeserializer yuvDeserializer(host->GetBuffer(), host->GetBufferSize()); 1.235 + ASSERT_TRUE(yuvDeserializer.IsValid()); 1.236 + PlanarYCbCrData data; 1.237 + data.mYChannel = yuvDeserializer.GetYData(); 1.238 + data.mCbChannel = yuvDeserializer.GetCbData(); 1.239 + data.mCrChannel = yuvDeserializer.GetCrData(); 1.240 + data.mYStride = yuvDeserializer.GetYStride(); 1.241 + data.mCbCrStride = yuvDeserializer.GetCbCrStride(); 1.242 + data.mStereoMode = yuvDeserializer.GetStereoMode(); 1.243 + data.mYSize = yuvDeserializer.GetYSize(); 1.244 + data.mCbCrSize = yuvDeserializer.GetCbCrSize(); 1.245 + data.mYSkip = 0; 1.246 + data.mCbSkip = 0; 1.247 + data.mCrSkip = 0; 1.248 + data.mPicSize = data.mYSize; 1.249 + data.mPicX = 0; 1.250 + data.mPicY = 0; 1.251 + 1.252 + AssertYCbCrSurfacesEqual(&ycbcrData, &data); 1.253 + host->Unlock(); 1.254 +} 1.255 + 1.256 +} // namespace 1.257 +} // namespace 1.258 + 1.259 +TEST(Layers, TextureSerialization) { 1.260 + // the test is run on all the following image formats 1.261 + gfxImageFormat formats[3] = { 1.262 + gfxImageFormat::ARGB32, 1.263 + gfxImageFormat::RGB24, 1.264 + gfxImageFormat::A8, 1.265 + }; 1.266 + 1.267 + for (int f = 0; f < 3; ++f) { 1.268 + RefPtr<gfxImageSurface> surface = new gfxImageSurface(gfxIntSize(400,300), formats[f]); 1.269 + SetupSurface(surface.get()); 1.270 + AssertSurfacesEqual(surface, surface); 1.271 + 1.272 + RefPtr<TextureClient> client 1.273 + = new MemoryTextureClient(nullptr, 1.274 + mozilla::gfx::ImageFormatToSurfaceFormat(surface->Format()), 1.275 + gfx::BackendType::CAIRO, 1.276 + TEXTURE_DEALLOCATE_CLIENT); 1.277 + 1.278 + TestTextureClientSurface(client, surface); 1.279 + 1.280 + // XXX - Test more texture client types. 1.281 + } 1.282 +} 1.283 + 1.284 +TEST(Layers, TextureYCbCrSerialization) { 1.285 + RefPtr<gfxImageSurface> ySurface = new gfxImageSurface(gfxIntSize(400,300), gfxImageFormat::A8); 1.286 + RefPtr<gfxImageSurface> cbSurface = new gfxImageSurface(gfxIntSize(200,150), gfxImageFormat::A8); 1.287 + RefPtr<gfxImageSurface> crSurface = new gfxImageSurface(gfxIntSize(200,150), gfxImageFormat::A8); 1.288 + SetupSurface(ySurface.get()); 1.289 + SetupSurface(cbSurface.get()); 1.290 + SetupSurface(crSurface.get()); 1.291 + 1.292 + PlanarYCbCrData clientData; 1.293 + clientData.mYChannel = ySurface->Data(); 1.294 + clientData.mCbChannel = cbSurface->Data(); 1.295 + clientData.mCrChannel = crSurface->Data(); 1.296 + clientData.mYSize = ySurface->GetSize().ToIntSize(); 1.297 + clientData.mPicSize = ySurface->GetSize().ToIntSize(); 1.298 + clientData.mCbCrSize = cbSurface->GetSize().ToIntSize(); 1.299 + clientData.mYStride = ySurface->Stride(); 1.300 + clientData.mCbCrStride = cbSurface->Stride(); 1.301 + clientData.mStereoMode = StereoMode::MONO; 1.302 + clientData.mYSkip = 0; 1.303 + clientData.mCbSkip = 0; 1.304 + clientData.mCrSkip = 0; 1.305 + clientData.mCrSkip = 0; 1.306 + clientData.mPicX = 0; 1.307 + clientData.mPicX = 0; 1.308 + 1.309 + RefPtr<TextureClient> client 1.310 + = new MemoryTextureClient(nullptr, 1.311 + mozilla::gfx::SurfaceFormat::YUV, 1.312 + gfx::BackendType::CAIRO, 1.313 + TEXTURE_DEALLOCATE_CLIENT); 1.314 + 1.315 + TestTextureClientYCbCr(client, clientData); 1.316 + 1.317 + // XXX - Test more texture client types. 1.318 +}