Bug 1068190 - Part 1: Add foundation for compositor unit tests. r=mstange

This commit is contained in:
Benoit Girard 2015-01-14 17:24:09 -05:00
Родитель 73ee83551b
Коммит 9b8c2dc37d
14 изменённых файлов: 363 добавлений и 38 удалений

Просмотреть файл

@ -389,10 +389,14 @@ size_t MacIOSurface::GetPlaneCount() {
}
/*static*/ size_t MacIOSurface::GetMaxWidth() {
if (!MacIOSurfaceLib::isInit())
return -1;
return MacIOSurfaceLib::IOSurfaceGetPropertyMaximum(MacIOSurfaceLib::kPropWidth);
}
/*static*/ size_t MacIOSurface::GetMaxHeight() {
if (!MacIOSurfaceLib::isInit())
return -1;
return MacIOSurfaceLib::IOSurfaceGetPropertyMaximum(MacIOSurfaceLib::kPropHeight);
}

Просмотреть файл

@ -9,6 +9,7 @@
#include "mozilla/layers/Effects.h" // for Effect, EffectChain, etc
#include "mozilla/mozalloc.h" // for operator delete, etc
#include "gfx2DGlue.h"
#include "nsAppRunner.h"
namespace mozilla {
namespace gfx {
@ -28,7 +29,7 @@ Compositor::GetBackend()
/* static */ void
Compositor::SetBackend(LayersBackend backend)
{
if (sBackend != LayersBackend::LAYERS_NONE && sBackend != backend) {
if (!gIsGtest && sBackend != LayersBackend::LAYERS_NONE && sBackend != backend) {
// Assert this once we figure out bug 972891.
//MOZ_CRASH("Trying to use more than one OMTC compositor.");

Просмотреть файл

@ -6,6 +6,7 @@
/* This must occur *after* layers/PLayers.h to avoid typedefs conflicts. */
#include "LayerScope.h"
#include "nsAppRunner.h"
#include "Composer2D.h"
#include "Effects.h"
#include "mozilla/TimeStamp.h"
@ -981,7 +982,7 @@ bool
LayerScope::CheckSendable()
{
// Only compositor threads check LayerScope status
MOZ_ASSERT(CompositorParent::IsInCompositorThread());
MOZ_ASSERT(CompositorParent::IsInCompositorThread() || gIsGtest);
if (!gfxPrefs::LayerScopeEnabled()) {
return false;

Просмотреть файл

@ -43,6 +43,7 @@
#include "ipc/CompositorBench.h" // for CompositorBench
#include "ipc/ShadowLayerUtils.h"
#include "mozilla/mozalloc.h" // for operator new, etc
#include "nsAppRunner.h"
#include "nsAutoPtr.h" // for nsRefPtr
#include "nsCOMPtr.h" // for already_AddRefed
#include "nsDebug.h" // for NS_WARNING, NS_RUNTIMEABORT, etc
@ -332,15 +333,19 @@ LayerManagerComposite::CreateOptimalMaskDrawTarget(const IntSize &aSize)
already_AddRefed<PaintedLayer>
LayerManagerComposite::CreatePaintedLayer()
{
NS_RUNTIMEABORT("Should only be called on the drawing side");
return nullptr;
MOZ_ASSERT(gIsGtest, "Unless you're testing the compositor using GTest,"
"this should only be called on the drawing side");
nsRefPtr<PaintedLayer> layer = new PaintedLayerComposite(this);
return layer.forget();
}
already_AddRefed<ContainerLayer>
LayerManagerComposite::CreateContainerLayer()
{
NS_RUNTIMEABORT("Should only be called on the drawing side");
return nullptr;
MOZ_ASSERT(gIsGtest, "Unless you're testing the compositor using GTest,"
"this should only be called on the drawing side");
nsRefPtr<ContainerLayer> layer = new ContainerLayerComposite(this);
return layer.forget();
}
already_AddRefed<ImageLayer>
@ -353,8 +358,10 @@ LayerManagerComposite::CreateImageLayer()
already_AddRefed<ColorLayer>
LayerManagerComposite::CreateColorLayer()
{
NS_RUNTIMEABORT("Should only be called on the drawing side");
return nullptr;
MOZ_ASSERT(gIsGtest, "Unless you're testing the compositor using GTest,"
"this should only be called on the drawing side");
nsRefPtr<ColorLayer> layer = new ColorLayerComposite(this);
return layer.forget();
}
already_AddRefed<CanvasLayer>

Просмотреть файл

@ -854,8 +854,8 @@ CompositorParent::CompositeCallback(TimeStamp aScheduleTime)
// Go down the composite layer tree, setting properties to match their
// content-side counterparts.
static void
SetShadowProperties(Layer* aLayer)
/* static */ void
CompositorParent::SetShadowProperties(Layer* aLayer)
{
// FIXME: Bug 717688 -- Do these updates in LayerTransactionParent::RecvUpdate.
LayerComposite* layerComposite = aLayer->AsLayerComposite();
@ -1672,7 +1672,7 @@ CrossProcessCompositorParent::ShadowLayersUpdated(
Layer* shadowRoot = aLayerTree->GetRoot();
if (shadowRoot) {
SetShadowProperties(shadowRoot);
CompositorParent::SetShadowProperties(shadowRoot);
}
UpdateIndirectTree(id, shadowRoot, aTargetConfig);

Просмотреть файл

@ -190,6 +190,8 @@ public:
void ForceIsFirstPaint();
void Destroy();
static void SetShadowProperties(Layer* aLayer);
void NotifyChildCreated(const uint64_t& aChild);
void AsyncRender();

Просмотреть файл

@ -29,6 +29,7 @@
#include "mozilla/layers/TextureHost.h" // for TextureSource, etc
#include "mozilla/layers/TextureHostOGL.h" // for TextureSourceOGL, etc
#include "mozilla/mozalloc.h" // for operator delete, etc
#include "nsAppRunner.h"
#include "nsAString.h"
#include "nsIConsoleService.h" // for nsIConsoleService, etc
#include "nsIWidget.h" // for nsIWidget
@ -104,6 +105,13 @@ CompositorOGL::CreateContext()
{
nsRefPtr<GLContext> context;
// Used by mock widget to create an offscreen context
void* widgetOpenGLContext = mWidget->GetNativeData(NS_NATIVE_OPENGL_CONTEXT);
if (widgetOpenGLContext) {
GLContext* alreadyRefed = reinterpret_cast<GLContext*>(widgetOpenGLContext);
return already_AddRefed<GLContext>(alreadyRefed);
}
#ifdef XP_WIN
if (PR_GetEnv("MOZ_LAYERS_PREFER_EGL")) {
printf_stderr("Trying GL layers...\n");
@ -435,7 +443,7 @@ CompositorOGL::PrepareViewport(const gfx::IntSize& aSize)
// Matrix to transform (0, 0, aWidth, aHeight) to viewport space (-1.0, 1.0,
// 2, 2) and flip the contents.
Matrix viewMatrix;
if (mGLContext->IsOffscreen()) {
if (mGLContext->IsOffscreen() && !gIsGtest) {
// In case of rendering via GL Offscreen context, disable Y-Flipping
viewMatrix.PreTranslate(-1.0, -1.0);
viewMatrix.PreScale(2.0f / float(aSize.width), 2.0f / float(aSize.height));

Просмотреть файл

@ -0,0 +1,267 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
#include "gfxUtils.h"
#include "gtest/gtest.h"
#include "TestLayers.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/RefPtr.h"
#include "mozilla/layers/BasicCompositor.h" // for BasicCompositor
#include "mozilla/layers/Compositor.h" // for Compositor
#include "mozilla/layers/CompositorOGL.h" // for CompositorOGL
#include "mozilla/layers/CompositorTypes.h"
#include "mozilla/layers/LayerManagerComposite.h"
#include "nsBaseWidget.h"
#include "GLContext.h"
#include "GLContextProvider.h"
#include <vector>
const int gCompWidth = 256;
const int gCompHeight = 256;
using namespace mozilla;
using namespace mozilla::gfx;
using namespace mozilla::layers;
using namespace mozilla::gl;
class MockWidget : public nsBaseWidget
{
public:
MockWidget() {}
NS_DECL_ISUPPORTS_INHERITED
NS_IMETHOD GetClientBounds(nsIntRect &aRect) {
aRect = nsIntRect(0, 0, gCompWidth, gCompHeight);
return NS_OK;
}
NS_IMETHOD GetBounds(nsIntRect &aRect) { return GetClientBounds(aRect); }
void* GetNativeData(uint32_t aDataType) MOZ_OVERRIDE {
if (aDataType == NS_NATIVE_OPENGL_CONTEXT) {
mozilla::gl::SurfaceCaps caps = mozilla::gl::SurfaceCaps::ForRGB();
caps.preserve = false;
caps.bpp16 = false;
nsRefPtr<GLContext> context = GLContextProvider::CreateOffscreen(
gfxIntSize(gCompWidth, gCompHeight), caps);
return context.forget().take();
}
return nullptr;
}
NS_IMETHOD Create(nsIWidget *aParent,
nsNativeWidget aNativeParent,
const nsIntRect &aRect,
nsDeviceContext *aContext,
nsWidgetInitData *aInitData = nullptr) { return NS_OK; }
NS_IMETHOD Show(bool aState) { return NS_OK; }
virtual bool IsVisible() const { return true; }
NS_IMETHOD ConstrainPosition(bool aAllowSlop,
int32_t *aX, int32_t *aY) { return NS_OK; }
NS_IMETHOD Move(double aX, double aY) { return NS_OK; }
NS_IMETHOD Resize(double aWidth, double aHeight, bool aRepaint) { return NS_OK; }
NS_IMETHOD Resize(double aX, double aY,
double aWidth, double aHeight, bool aRepaint) { return NS_OK; }
NS_IMETHOD Enable(bool aState) { return NS_OK; }
virtual bool IsEnabled() const { return true; }
NS_IMETHOD SetFocus(bool aRaise) { return NS_OK; }
virtual nsresult ConfigureChildren(const nsTArray<Configuration>& aConfigurations) { return NS_OK; }
NS_IMETHOD Invalidate(const nsIntRect &aRect) { return NS_OK; }
NS_IMETHOD SetTitle(const nsAString& title) { return NS_OK; }
virtual nsIntPoint WidgetToScreenOffset() { return nsIntPoint(0, 0); }
NS_IMETHOD DispatchEvent(mozilla::WidgetGUIEvent* aEvent,
nsEventStatus& aStatus) { return NS_OK; }
NS_IMETHOD CaptureRollupEvents(nsIRollupListener * aListener, bool aDoCapture) { return NS_OK; }
NS_IMETHOD_(void) SetInputContext(const InputContext& aContext,
const InputContextAction& aAction) {}
NS_IMETHOD_(InputContext) GetInputContext() { abort(); }
NS_IMETHOD ReparentNativeWidget(nsIWidget* aNewParent) { return NS_OK; }
private:
~MockWidget() {}
};
NS_IMPL_ISUPPORTS_INHERITED0(MockWidget, nsBaseWidget)
struct LayerManagerData {
RefPtr<MockWidget> mWidget;
RefPtr<Compositor> mCompositor;
nsRefPtr<LayerManagerComposite> mLayerManager;
LayerManagerData(Compositor* compositor, MockWidget* widget, LayerManagerComposite* layerManager)
: mWidget(widget)
, mCompositor(compositor)
, mLayerManager(layerManager)
{}
};
static TemporaryRef<Compositor> CreateTestCompositor(LayersBackend backend, MockWidget* widget)
{
gfxPrefs::GetSingleton();
RefPtr<Compositor> compositor;
if (backend == LayersBackend::LAYERS_OPENGL) {
compositor = new CompositorOGL(widget,
gCompWidth,
gCompHeight,
true);
compositor->SetDestinationSurfaceSize(IntSize(gCompWidth, gCompHeight));
} else if (backend == LayersBackend::LAYERS_BASIC) {
compositor = new BasicCompositor(widget);
#ifdef XP_WIN
} else if (backend == LayersBackend::LAYERS_D3D11) {
//compositor = new CompositorD3D11();
MOZ_CRASH(); // No support yet
} else if (backend == LayersBackend::LAYERS_D3D9) {
//compositor = new CompositorD3D9(this, mWidget);
MOZ_CRASH(); // No support yet
#endif
}
if (!compositor) {
printf_stderr("Failed to construct layer manager for the requested backend\n");
abort();
}
return compositor;
}
/**
* Get a list of layers managers for the platform to run the test on.
*/
static std::vector<LayerManagerData> GetLayerManagers(std::vector<LayersBackend> aBackends)
{
std::vector<LayerManagerData> managers;
for (size_t i = 0; i < aBackends.size(); i++) {
auto backend = aBackends[i];
RefPtr<MockWidget> widget = new MockWidget();
RefPtr<Compositor> compositor = CreateTestCompositor(backend, widget);
nsRefPtr<LayerManagerComposite> layerManager = new LayerManagerComposite(compositor);
layerManager->Initialize();
managers.push_back(LayerManagerData(compositor, widget, layerManager));
}
return managers;
}
/**
* This will return the default list of backends that
* units test should run against.
*/
static std::vector<LayersBackend> GetPlatformBackends()
{
std::vector<LayersBackend> backends;
// For now we only support Basic for gtest
backends.push_back(LayersBackend::LAYERS_BASIC);
#ifdef XP_MACOSX
backends.push_back(LayersBackend::LAYERS_OPENGL);
#endif
// TODO Support OGL/D3D backends with unit test
return backends;
}
static TemporaryRef<DrawTarget> CreateDT()
{
RefPtr<DrawTarget> dt = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(
IntSize(gCompWidth, gCompHeight), SurfaceFormat::B8G8R8A8);
return dt;
}
static bool CompositeAndCompare(nsRefPtr<LayerManagerComposite> layerManager, DrawTarget* refDT)
{
RefPtr<DrawTarget> drawTarget = CreateDT();
layerManager->BeginTransactionWithDrawTarget(drawTarget, nsIntRect(0, 0, gCompWidth, gCompHeight));
layerManager->EndEmptyTransaction();
RefPtr<SourceSurface> ss = drawTarget->Snapshot();
RefPtr<DataSourceSurface> dss = ss->GetDataSurface();
uint8_t* bitmap = dss->GetData();
RefPtr<SourceSurface> ssRef = refDT->Snapshot();
RefPtr<DataSourceSurface> dssRef = ssRef->GetDataSurface();
uint8_t* bitmapRef = dssRef->GetData();
for (int y = 0; y < gCompHeight; y++) {
for (int x = 0; x < gCompWidth; x++) {
for (size_t channel = 0; channel < 4; channel++) {
uint8_t bit = bitmap[y * dss->Stride() + x * 4 + channel];
uint8_t bitRef = bitmapRef[y * dss->Stride() + x * 4 + channel];
if (bit != bitRef) {
printf("Layer Tree:\n");
layerManager->Dump();
printf("Original:\n");
gfxUtils::DumpAsDataURI(drawTarget);
printf("\n\n");
printf("Reference:\n");
gfxUtils::DumpAsDataURI(refDT);
printf("\n\n");
return false;
}
}
}
}
return true;
}
TEST(Gfx, CompositorConstruct)
{
auto layerManagers = GetLayerManagers(GetPlatformBackends());
}
TEST(Gfx, CompositorSimpleTree)
{
auto layerManagers = GetLayerManagers(GetPlatformBackends());
for (size_t i = 0; i < layerManagers.size(); i++) {
nsRefPtr<LayerManagerComposite> layerManager = layerManagers[i].mLayerManager;
nsRefPtr<LayerManager> lmBase = layerManager.get();
nsTArray<nsRefPtr<Layer>> layers;
nsIntRegion layerVisibleRegion[] = {
nsIntRegion(nsIntRect(0, 0, gCompWidth, gCompHeight)),
nsIntRegion(nsIntRect(0, 0, gCompWidth, gCompHeight)),
nsIntRegion(nsIntRect(0, 0, 100, 100)),
nsIntRegion(nsIntRect(0, 50, 100, 100)),
};
nsRefPtr<Layer> root = CreateLayerTree("c(ooo)", layerVisibleRegion, nullptr, lmBase, layers);
{ // background
ColorLayer* colorLayer = layers[1]->AsColorLayer();
colorLayer->SetColor(gfxRGBA(1.f, 0.f, 1.f, 1.f));
colorLayer->SetBounds(colorLayer->GetVisibleRegion().GetBounds());
}
{
ColorLayer* colorLayer = layers[2]->AsColorLayer();
colorLayer->SetColor(gfxRGBA(1.f, 0.f, 0.f, 1.f));
colorLayer->SetBounds(colorLayer->GetVisibleRegion().GetBounds());
}
{
ColorLayer* colorLayer = layers[3]->AsColorLayer();
colorLayer->SetColor(gfxRGBA(0.f, 0.f, 1.f, 1.f));
colorLayer->SetBounds(colorLayer->GetVisibleRegion().GetBounds());
}
RefPtr<DrawTarget> refDT = CreateDT();
refDT->FillRect(Rect(0, 0, gCompWidth, gCompHeight), ColorPattern(Color(1.f, 0.f, 1.f, 1.f)));
refDT->FillRect(Rect(0, 0, 100, 100), ColorPattern(Color(1.f, 0.f, 0.f, 1.f)));
refDT->FillRect(Rect(0, 50, 100, 100), ColorPattern(Color(0.f, 0.f, 1.f, 1.f)));
EXPECT_TRUE(CompositeAndCompare(layerManager, refDT));
}
}

Просмотреть файл

@ -7,34 +7,12 @@
#include "gtest/gtest.h"
#include "gmock/gmock.h"
#include "mozilla/layers/LayerMetricsWrapper.h"
#include "mozilla/layers/CompositorParent.h"
using namespace mozilla;
using namespace mozilla::gfx;
using namespace mozilla::layers;
class TestLayerManager: public LayerManager {
public:
TestLayerManager()
: LayerManager()
{}
virtual bool EndEmptyTransaction(EndTransactionFlags aFlags = END_DEFAULT) { return false; }
virtual already_AddRefed<ContainerLayer> CreateContainerLayer() { return nullptr; }
virtual void GetBackendName(nsAString& aName) {}
virtual LayersBackend GetBackendType() { return LayersBackend::LAYERS_BASIC; }
virtual void BeginTransaction() {}
virtual already_AddRefed<ImageLayer> CreateImageLayer() { return nullptr; }
virtual void SetRoot(Layer* aLayer) {}
virtual already_AddRefed<ColorLayer> CreateColorLayer() { return nullptr; }
virtual void BeginTransactionWithTarget(gfxContext* aTarget) {}
virtual already_AddRefed<CanvasLayer> CreateCanvasLayer() { return nullptr; }
virtual void EndTransaction(DrawPaintedLayerCallback aCallback,
void* aCallbackData,
EndTransactionFlags aFlags = END_DEFAULT) {}
virtual int32_t GetMaxTextureSize() const { return 0; }
virtual already_AddRefed<PaintedLayer> CreatePaintedLayer() { return nullptr; }
};
class TestContainerLayer: public ContainerLayer {
public:
explicit TestContainerLayer(LayerManager* aManager)
@ -73,6 +51,44 @@ public:
}
};
class TestLayerManager: public LayerManager {
public:
TestLayerManager()
: LayerManager()
{}
virtual bool EndEmptyTransaction(EndTransactionFlags aFlags = END_DEFAULT) { return false; }
virtual already_AddRefed<ContainerLayer> CreateContainerLayer() {
nsRefPtr<ContainerLayer> layer = new TestContainerLayer(this);
return layer.forget();
}
virtual void GetBackendName(nsAString& aName) {}
virtual LayersBackend GetBackendType() { return LayersBackend::LAYERS_BASIC; }
virtual void BeginTransaction() {}
virtual already_AddRefed<ImageLayer> CreateImageLayer() {
NS_RUNTIMEABORT("Not implemented.");
return nullptr;
}
virtual already_AddRefed<PaintedLayer> CreatePaintedLayer() {
nsRefPtr<PaintedLayer> layer = new TestPaintedLayer(this);
return layer.forget();
}
virtual already_AddRefed<ColorLayer> CreateColorLayer() {
NS_RUNTIMEABORT("Not implemented.");
return nullptr;
}
virtual void SetRoot(Layer* aLayer) {}
virtual void BeginTransactionWithTarget(gfxContext* aTarget) {}
virtual already_AddRefed<CanvasLayer> CreateCanvasLayer() {
NS_RUNTIMEABORT("Not implemented.");
return nullptr;
}
virtual void EndTransaction(DrawPaintedLayerCallback aCallback,
void* aCallbackData,
EndTransactionFlags aFlags = END_DEFAULT) {}
virtual int32_t GetMaxTextureSize() const { return 0; }
};
class TestUserData: public LayerUserData {
public:
MOCK_METHOD0(Die, void());
@ -153,9 +169,11 @@ static
already_AddRefed<Layer> CreateLayer(char aLayerType, LayerManager* aManager) {
nsRefPtr<Layer> layer = nullptr;
if (aLayerType == 'c') {
layer = new TestContainerLayer(aManager);
layer = aManager->CreateContainerLayer();
} else if (aLayerType == 't') {
layer = new TestPaintedLayer(aManager);
layer = aManager->CreatePaintedLayer();
} else if (aLayerType == 'o') {
layer = aManager->CreateColorLayer();
}
return layer.forget();
}
@ -169,7 +187,9 @@ already_AddRefed<Layer> CreateLayerTree(
aLayersOut.Clear();
if (!manager) {
manager = new TestLayerManager();
}
nsRefPtr<Layer> rootLayer = nullptr;
nsRefPtr<ContainerLayer> parentContainerLayer = nullptr;
@ -215,6 +235,11 @@ already_AddRefed<Layer> CreateLayerTree(
}
if (rootLayer) {
rootLayer->ComputeEffectiveTransforms(Matrix4x4());
manager->SetRoot(rootLayer);
if (rootLayer->AsLayerComposite()) {
// Only perform this for LayerManagerComposite
CompositorParent::SetShadowProperties(rootLayer);
}
}
return rootLayer.forget();
}

Просмотреть файл

@ -11,6 +11,7 @@ UNIFIED_SOURCES += [
'TestAsyncPanZoomController.cpp',
'TestBufferRotation.cpp',
'TestColorNames.cpp',
'TestCompositor.cpp',
'TestGfxPrefs.cpp',
'TestLayers.cpp',
'TestRegion.cpp',

Просмотреть файл

@ -20,6 +20,8 @@ if CONFIG['OS_ARCH'] == 'WINNT':
XPIDL_MODULE = 'xulapp'
EXPORTS += ['nsAppRunner.h']
if CONFIG['MOZ_INSTRUMENT_EVENT_LOOP']:
EXPORTS += ['EventTracer.h']

Просмотреть файл

@ -214,6 +214,8 @@ static nsIProfileLock* gProfileLock;
int gRestartArgc;
char **gRestartArgv;
bool gIsGtest = false;
#ifdef MOZ_WIDGET_QT
static int gQtOnlyArgc;
static char **gQtOnlyArgv;
@ -3559,7 +3561,9 @@ XREMain::XRE_mainStartup(bool* aExitFlag)
#endif
// RunGTest will only be set if we're in xul-unit
if (mozilla::RunGTest) {
gIsGtest = true;
result = mozilla::RunGTest();
gIsGtest = false;
} else {
result = 1;
printf("TEST-UNEXPECTED-FAIL | gtest | Not compiled with enable-tests\n");

Просмотреть файл

@ -58,6 +58,8 @@ extern int gRestartArgc;
extern char **gRestartArgv;
extern bool gLogConsoleErrors;
extern bool gIsGtest;
/**
* Create the nativeappsupport implementation.
*

Просмотреть файл

@ -91,6 +91,7 @@ typedef void* nsNativeWidget;
// Has to match to NPNVnetscapeWindow, and shareable across processes
// HWND on Windows and XID on X11
#define NS_NATIVE_SHAREABLE_WINDOW 11
#define NS_NATIVE_OPENGL_CONTEXT 12
#ifdef XP_MACOSX
#define NS_NATIVE_PLUGIN_PORT_QD 100
#define NS_NATIVE_PLUGIN_PORT_CG 101