mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-16 14:55:47 +00:00
Bug 1144103 - Support screen recording r=mwu
This commit is contained in:
parent
06874d3f1e
commit
88d1681a84
@ -310,6 +310,7 @@ private:
|
|||||||
DECL_GFX_PREF(Once, "layers.componentalpha.enabled", ComponentAlphaEnabled, bool, true);
|
DECL_GFX_PREF(Once, "layers.componentalpha.enabled", ComponentAlphaEnabled, bool, true);
|
||||||
#endif
|
#endif
|
||||||
DECL_GFX_PREF(Live, "layers.composer2d.enabled", Composer2DCompositionEnabled, bool, false);
|
DECL_GFX_PREF(Live, "layers.composer2d.enabled", Composer2DCompositionEnabled, bool, false);
|
||||||
|
DECL_GFX_PREF(Live, "layers.screen-recording.enabled", ScreenRecordingEnabled, bool, false);
|
||||||
DECL_GFX_PREF(Once, "layers.d3d11.disable-warp", LayersD3D11DisableWARP, bool, false);
|
DECL_GFX_PREF(Once, "layers.d3d11.disable-warp", LayersD3D11DisableWARP, bool, false);
|
||||||
DECL_GFX_PREF(Once, "layers.d3d11.force-warp", LayersD3D11ForceWARP, bool, false);
|
DECL_GFX_PREF(Once, "layers.d3d11.force-warp", LayersD3D11ForceWARP, bool, false);
|
||||||
DECL_GFX_PREF(Live, "layers.deaa.enabled", LayersDEAAEnabled, bool, false);
|
DECL_GFX_PREF(Live, "layers.deaa.enabled", LayersDEAAEnabled, bool, false);
|
||||||
|
@ -15,19 +15,32 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define LOG_TAG "FakeSurfaceComposer"
|
||||||
|
//#define LOG_NDEBUG 0
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <cutils/log.h>
|
#include <cutils/log.h>
|
||||||
|
#include <cutils/properties.h>
|
||||||
|
|
||||||
#include <gui/IDisplayEventConnection.h>
|
#include <gui/IDisplayEventConnection.h>
|
||||||
#include <gui/GraphicBufferAlloc.h>
|
#include <gui/GraphicBufferAlloc.h>
|
||||||
|
#include <ui/DisplayInfo.h>
|
||||||
|
|
||||||
#if ANDROID_VERSION >= 21
|
#if ANDROID_VERSION >= 21
|
||||||
#include <ui/Rect.h>
|
#include <ui/Rect.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "../libdisplay/GonkDisplay.h"
|
||||||
|
#include "../nsScreenManagerGonk.h"
|
||||||
#include "FakeSurfaceComposer.h"
|
#include "FakeSurfaceComposer.h"
|
||||||
|
#include "gfxPrefs.h"
|
||||||
|
#include "MainThreadUtils.h"
|
||||||
|
#include "mozilla/Assertions.h"
|
||||||
|
#include "nsThreadUtils.h"
|
||||||
|
|
||||||
|
using namespace mozilla;
|
||||||
|
|
||||||
namespace android {
|
namespace android {
|
||||||
|
|
||||||
@ -57,20 +70,91 @@ sp<IGraphicBufferAlloc> FakeSurfaceComposer::createGraphicBufferAlloc()
|
|||||||
return gba;
|
return gba;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class DestroyDisplayRunnable : public nsRunnable {
|
||||||
|
public:
|
||||||
|
DestroyDisplayRunnable(FakeSurfaceComposer* aComposer, ssize_t aIndex)
|
||||||
|
: mComposer(aComposer), mIndex(aIndex) { }
|
||||||
|
NS_IMETHOD Run() override {
|
||||||
|
MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
|
||||||
|
Mutex::Autolock _l(mComposer->mStateLock);
|
||||||
|
RefPtr<nsScreenManagerGonk> screenManager =
|
||||||
|
nsScreenManagerGonk::GetInstance();
|
||||||
|
screenManager->RemoveScreen(GonkDisplay::DISPLAY_VIRTUAL);
|
||||||
|
mComposer->mDisplays.removeItemsAt(mIndex);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
sp<FakeSurfaceComposer> mComposer;
|
||||||
|
ssize_t mIndex;
|
||||||
|
};
|
||||||
|
|
||||||
sp<IBinder> FakeSurfaceComposer::createDisplay(const String8& displayName,
|
sp<IBinder> FakeSurfaceComposer::createDisplay(const String8& displayName,
|
||||||
bool secure)
|
bool secure)
|
||||||
{
|
{
|
||||||
|
#if ANDROID_VERSION >= 19
|
||||||
|
class DisplayToken : public BBinder {
|
||||||
|
sp<FakeSurfaceComposer> composer;
|
||||||
|
virtual ~DisplayToken() {
|
||||||
|
MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
|
||||||
|
// no more references, this display must be terminated
|
||||||
|
Mutex::Autolock _l(composer->mStateLock);
|
||||||
|
ssize_t idx = composer->mDisplays.indexOfKey(this);
|
||||||
|
if (idx >= 0) {
|
||||||
|
nsCOMPtr<nsIRunnable> task(new DestroyDisplayRunnable(composer.get(), idx));
|
||||||
|
NS_DispatchToMainThread(task);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
DisplayToken(const sp<FakeSurfaceComposer>& composer)
|
||||||
|
: composer(composer) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!gfxPrefs::ScreenRecordingEnabled()) {
|
||||||
|
ALOGE("screen recording is not permitted");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
sp<BBinder> token = new DisplayToken(this);
|
||||||
|
|
||||||
|
Mutex::Autolock _l(mStateLock);
|
||||||
|
DisplayDeviceState info(HWC_DISPLAY_VIRTUAL);
|
||||||
|
info.displayName = displayName;
|
||||||
|
info.displayId = GonkDisplay::DISPLAY_VIRTUAL;
|
||||||
|
info.isSecure = secure;
|
||||||
|
mDisplays.add(token, info);
|
||||||
|
return token;
|
||||||
|
#else
|
||||||
|
return nullptr;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID_VERSION >= 19
|
#if ANDROID_VERSION >= 19
|
||||||
void FakeSurfaceComposer::destroyDisplay(const sp<IBinder>& display)
|
void FakeSurfaceComposer::destroyDisplay(const sp<IBinder>& display)
|
||||||
{
|
{
|
||||||
|
Mutex::Autolock _l(mStateLock);
|
||||||
|
|
||||||
|
ssize_t idx = mDisplays.indexOfKey(display);
|
||||||
|
if (idx < 0) {
|
||||||
|
ALOGW("destroyDisplay: invalid display token");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsIRunnable> task(new DestroyDisplayRunnable(this, idx));
|
||||||
|
NS_DispatchToMainThread(task);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
sp<IBinder> FakeSurfaceComposer::getBuiltInDisplay(int32_t id) {
|
sp<IBinder> FakeSurfaceComposer::getBuiltInDisplay(int32_t id)
|
||||||
return nullptr;
|
{
|
||||||
|
// support only primary display
|
||||||
|
if (uint32_t(id) != HWC_DISPLAY_PRIMARY) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mPrimaryDisplay.get()) {
|
||||||
|
mPrimaryDisplay = new BBinder();
|
||||||
|
}
|
||||||
|
return mPrimaryDisplay;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FakeSurfaceComposer::setTransactionState(
|
void FakeSurfaceComposer::setTransactionState(
|
||||||
@ -78,6 +162,79 @@ void FakeSurfaceComposer::setTransactionState(
|
|||||||
const Vector<DisplayState>& displays,
|
const Vector<DisplayState>& displays,
|
||||||
uint32_t flags)
|
uint32_t flags)
|
||||||
{
|
{
|
||||||
|
Mutex::Autolock _l(mStateLock);
|
||||||
|
size_t count = displays.size();
|
||||||
|
for (size_t i=0 ; i<count ; i++) {
|
||||||
|
const DisplayState& s(displays[i]);
|
||||||
|
setDisplayStateLocked(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t FakeSurfaceComposer::setDisplayStateLocked(const DisplayState& s)
|
||||||
|
{
|
||||||
|
ssize_t dpyIdx = mDisplays.indexOfKey(s.token);
|
||||||
|
if (dpyIdx < 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t flags = 0;
|
||||||
|
DisplayDeviceState& disp(mDisplays.editValueAt(dpyIdx));
|
||||||
|
|
||||||
|
if (!disp.isValid()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32_t what = s.what;
|
||||||
|
if (what & DisplayState::eSurfaceChanged) {
|
||||||
|
if (disp.surface->asBinder() != s.surface->asBinder()) {
|
||||||
|
disp.surface = s.surface;
|
||||||
|
flags |= eDisplayTransactionNeeded;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (what & DisplayState::eLayerStackChanged) {
|
||||||
|
if (disp.layerStack != s.layerStack) {
|
||||||
|
disp.layerStack = s.layerStack;
|
||||||
|
flags |= eDisplayTransactionNeeded;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (what & DisplayState::eDisplayProjectionChanged) {
|
||||||
|
if (disp.orientation != s.orientation) {
|
||||||
|
disp.orientation = s.orientation;
|
||||||
|
flags |= eDisplayTransactionNeeded;
|
||||||
|
}
|
||||||
|
if (disp.frame != s.frame) {
|
||||||
|
disp.frame = s.frame;
|
||||||
|
flags |= eDisplayTransactionNeeded;
|
||||||
|
}
|
||||||
|
if (disp.viewport != s.viewport) {
|
||||||
|
disp.viewport = s.viewport;
|
||||||
|
flags |= eDisplayTransactionNeeded;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if ANDROID_VERSION >= 21
|
||||||
|
if (what & DisplayState::eDisplaySizeChanged) {
|
||||||
|
if (disp.width != s.width) {
|
||||||
|
disp.width = s.width;
|
||||||
|
flags |= eDisplayTransactionNeeded;
|
||||||
|
}
|
||||||
|
if (disp.height != s.height) {
|
||||||
|
disp.height = s.height;
|
||||||
|
flags |= eDisplayTransactionNeeded;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (what & DisplayState::eSurfaceChanged) {
|
||||||
|
nsCOMPtr<nsIRunnable> runnable =
|
||||||
|
NS_NewRunnableFunction([&]() {
|
||||||
|
MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
|
||||||
|
RefPtr<nsScreenManagerGonk> screenManager = nsScreenManagerGonk::GetInstance();
|
||||||
|
screenManager->AddScreen(GonkDisplay::DISPLAY_VIRTUAL, disp.surface.get());
|
||||||
|
});
|
||||||
|
NS_DispatchToMainThread(runnable, NS_DISPATCH_SYNC);
|
||||||
|
}
|
||||||
|
|
||||||
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FakeSurfaceComposer::bootFinished()
|
void FakeSurfaceComposer::bootFinished()
|
||||||
@ -123,7 +280,27 @@ FakeSurfaceComposer::setPowerMode(const sp<IBinder>& display, int mode)
|
|||||||
status_t
|
status_t
|
||||||
FakeSurfaceComposer::getDisplayConfigs(const sp<IBinder>& display, Vector<DisplayInfo>* configs)
|
FakeSurfaceComposer::getDisplayConfigs(const sp<IBinder>& display, Vector<DisplayInfo>* configs)
|
||||||
{
|
{
|
||||||
return INVALID_OPERATION;
|
if (configs == NULL) {
|
||||||
|
return BAD_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Limit DisplayConfigs only to primary display
|
||||||
|
if (!display.get() || display != mPrimaryDisplay) {
|
||||||
|
return NAME_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
configs->clear();
|
||||||
|
DisplayInfo info = DisplayInfo();
|
||||||
|
|
||||||
|
nsCOMPtr<nsIRunnable> runnable =
|
||||||
|
NS_NewRunnableFunction([&]() {
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
getPrimaryDisplayInfo(&info);
|
||||||
|
});
|
||||||
|
NS_DispatchToMainThread(runnable, NS_DISPATCH_SYNC);
|
||||||
|
|
||||||
|
configs->push_back(info);
|
||||||
|
return NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
@ -135,6 +312,10 @@ FakeSurfaceComposer::getDisplayStats(const sp<IBinder>& display, DisplayStatInfo
|
|||||||
int
|
int
|
||||||
FakeSurfaceComposer::getActiveConfig(const sp<IBinder>& display)
|
FakeSurfaceComposer::getActiveConfig(const sp<IBinder>& display)
|
||||||
{
|
{
|
||||||
|
// Only support primary display.
|
||||||
|
if (display.get() && (display == mPrimaryDisplay)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
return INVALID_OPERATION;
|
return INVALID_OPERATION;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -169,8 +350,95 @@ FakeSurfaceComposer::unblank(const sp<IBinder>& display)
|
|||||||
status_t
|
status_t
|
||||||
FakeSurfaceComposer::getDisplayInfo(const sp<IBinder>& display, DisplayInfo* info)
|
FakeSurfaceComposer::getDisplayInfo(const sp<IBinder>& display, DisplayInfo* info)
|
||||||
{
|
{
|
||||||
return INVALID_OPERATION;
|
if (info == NULL) {
|
||||||
|
return BAD_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Limit DisplayConfigs only to primary display
|
||||||
|
if (!display.get() || display != mPrimaryDisplay) {
|
||||||
|
return NAME_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsIRunnable> runnable =
|
||||||
|
NS_NewRunnableFunction([&]() {
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
getPrimaryDisplayInfo(info);
|
||||||
|
});
|
||||||
|
NS_DispatchToMainThread(runnable, NS_DISPATCH_SYNC);
|
||||||
|
|
||||||
|
return NO_ERROR;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define VSYNC_EVENT_PHASE_OFFSET_NS 0
|
||||||
|
#define SF_VSYNC_EVENT_PHASE_OFFSET_NS 0
|
||||||
|
|
||||||
|
void
|
||||||
|
FakeSurfaceComposer::getPrimaryDisplayInfo(DisplayInfo* info)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
|
||||||
|
|
||||||
|
// Implementation mimic android SurfaceFlinger::getDisplayConfigs().
|
||||||
|
|
||||||
|
class Density {
|
||||||
|
static int getDensityFromProperty(char const* propName) {
|
||||||
|
char property[PROPERTY_VALUE_MAX];
|
||||||
|
int density = 0;
|
||||||
|
if (property_get(propName, property, NULL) > 0) {
|
||||||
|
density = atoi(property);
|
||||||
|
}
|
||||||
|
return density;
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
static int getEmuDensity() {
|
||||||
|
return getDensityFromProperty("qemu.sf.lcd_density"); }
|
||||||
|
static int getBuildDensity() {
|
||||||
|
return getDensityFromProperty("ro.sf.lcd_density"); }
|
||||||
|
};
|
||||||
|
|
||||||
|
RefPtr<nsScreenGonk> screen = nsScreenManagerGonk::GetPrimaryScreen();
|
||||||
|
|
||||||
|
float xdpi = screen->GetDpi();
|
||||||
|
float ydpi = screen->GetDpi();
|
||||||
|
int fps = 60; // XXX set a value from hwc hal
|
||||||
|
nsIntRect screenBounds = screen->GetNaturalBounds().ToUnknownRect();
|
||||||
|
|
||||||
|
// The density of the device is provided by a build property
|
||||||
|
float density = Density::getBuildDensity() / 160.0f;
|
||||||
|
if (density == 0) {
|
||||||
|
// the build doesn't provide a density -- this is wrong!
|
||||||
|
// use xdpi instead
|
||||||
|
ALOGE("ro.sf.lcd_density must be defined as a build property");
|
||||||
|
density = xdpi / 160.0f;
|
||||||
|
}
|
||||||
|
info->density = density;
|
||||||
|
info->orientation = screen->EffectiveScreenRotation();
|
||||||
|
|
||||||
|
info->w = screenBounds.width;
|
||||||
|
info->h = screenBounds.height;
|
||||||
|
info->xdpi = xdpi;
|
||||||
|
info->ydpi = ydpi;
|
||||||
|
info->fps = fps;
|
||||||
|
#if ANDROID_VERSION >= 21
|
||||||
|
info->appVsyncOffset = VSYNC_EVENT_PHASE_OFFSET_NS;
|
||||||
|
|
||||||
|
// This is how far in advance a buffer must be queued for
|
||||||
|
// presentation at a given time. If you want a buffer to appear
|
||||||
|
// on the screen at time N, you must submit the buffer before
|
||||||
|
// (N - presentationDeadline).
|
||||||
|
//
|
||||||
|
// Normally it's one full refresh period (to give SF a chance to
|
||||||
|
// latch the buffer), but this can be reduced by configuring a
|
||||||
|
// DispSync offset. Any additional delays introduced by the hardware
|
||||||
|
// composer or panel must be accounted for here.
|
||||||
|
//
|
||||||
|
// We add an additional 1ms to allow for processing time and
|
||||||
|
// differences between the ideal and actual refresh rate.
|
||||||
|
info->presentationDeadline =
|
||||||
|
(1e9 / fps) - SF_VSYNC_EVENT_PHASE_OFFSET_NS + 1000000;
|
||||||
|
#endif
|
||||||
|
// All non-virtual displays are currently considered secure.
|
||||||
|
info->secure = true;
|
||||||
|
}
|
||||||
|
|
||||||
}; // namespace android
|
}; // namespace android
|
||||||
|
@ -25,8 +25,14 @@
|
|||||||
|
|
||||||
#include <binder/BinderService.h>
|
#include <binder/BinderService.h>
|
||||||
|
|
||||||
|
#include <gui/IGraphicBufferProducer.h>
|
||||||
#include <gui/ISurfaceComposer.h>
|
#include <gui/ISurfaceComposer.h>
|
||||||
#include <gui/ISurfaceComposerClient.h>
|
#include <gui/ISurfaceComposerClient.h>
|
||||||
|
#include <hardware/hwcomposer.h>
|
||||||
|
#include <private/gui/LayerState.h>
|
||||||
|
#include <utils/KeyedVector.h>
|
||||||
|
|
||||||
|
class nsIWidget;
|
||||||
|
|
||||||
namespace android {
|
namespace android {
|
||||||
|
|
||||||
@ -34,6 +40,13 @@ namespace android {
|
|||||||
|
|
||||||
class IGraphicBufferAlloc;
|
class IGraphicBufferAlloc;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
eTransactionNeeded = 0x01,
|
||||||
|
eTraversalNeeded = 0x02,
|
||||||
|
eDisplayTransactionNeeded = 0x04,
|
||||||
|
eTransactionMask = 0x07
|
||||||
|
};
|
||||||
|
|
||||||
class FakeSurfaceComposer : public BinderService<FakeSurfaceComposer>,
|
class FakeSurfaceComposer : public BinderService<FakeSurfaceComposer>,
|
||||||
public BnSurfaceComposer
|
public BnSurfaceComposer
|
||||||
{
|
{
|
||||||
@ -102,7 +115,45 @@ private:
|
|||||||
virtual void unblank(const sp<IBinder>& display);
|
virtual void unblank(const sp<IBinder>& display);
|
||||||
virtual status_t getDisplayInfo(const sp<IBinder>& display, DisplayInfo* info);
|
virtual status_t getDisplayInfo(const sp<IBinder>& display, DisplayInfo* info);
|
||||||
#endif
|
#endif
|
||||||
|
void getPrimaryDisplayInfo(DisplayInfo* info);
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------
|
||||||
|
* Transactions
|
||||||
|
*/
|
||||||
|
uint32_t setDisplayStateLocked(const DisplayState& s);
|
||||||
|
|
||||||
|
sp<IBinder> mPrimaryDisplay;
|
||||||
|
|
||||||
|
struct DisplayDeviceState {
|
||||||
|
enum {
|
||||||
|
NO_LAYER_STACK = 0xFFFFFFFF,
|
||||||
|
};
|
||||||
|
DisplayDeviceState()
|
||||||
|
: type(-1), displayId(-1), width(0), height(0) {
|
||||||
|
}
|
||||||
|
DisplayDeviceState(int type)
|
||||||
|
: type(type), displayId(-1), layerStack(NO_LAYER_STACK), orientation(0), width(0), height(0) {
|
||||||
|
viewport.makeInvalid();
|
||||||
|
frame.makeInvalid();
|
||||||
|
}
|
||||||
|
bool isValid() const { return type >= 0; }
|
||||||
|
int type;
|
||||||
|
int displayId;
|
||||||
|
sp<IGraphicBufferProducer> surface;
|
||||||
|
uint32_t layerStack;
|
||||||
|
Rect viewport;
|
||||||
|
Rect frame;
|
||||||
|
uint8_t orientation;
|
||||||
|
uint32_t width, height;
|
||||||
|
String8 displayName;
|
||||||
|
bool isSecure;
|
||||||
|
};
|
||||||
|
|
||||||
|
// access must be protected by mStateLock
|
||||||
|
mutable Mutex mStateLock;
|
||||||
|
DefaultKeyedVector<wp<IBinder>, DisplayDeviceState> mDisplays;
|
||||||
|
|
||||||
|
friend class DestroyDisplayRunnable;
|
||||||
};
|
};
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
Loading…
Reference in New Issue
Block a user