Remove native calls to HWUI from Surface and use the public API instead
Test: CtsGraphicsTestCases and CtsWindowManagerDeviceTestCases Bug: 137655431 Change-Id: I8427f96e4f33905e8cabb6d48a0cc29443b9ed63
This commit is contained in:
@@ -23,6 +23,7 @@ import android.content.res.CompatibilityInfo.Translator;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.ColorSpace;
|
||||
import android.graphics.GraphicBuffer;
|
||||
import android.graphics.HardwareRenderer;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.RecordingCanvas;
|
||||
import android.graphics.Rect;
|
||||
@@ -925,7 +926,7 @@ public class Surface implements Parcelable {
|
||||
|
||||
private final class HwuiContext {
|
||||
private final RenderNode mRenderNode;
|
||||
private long mHwuiRenderer;
|
||||
private HardwareRenderer mHardwareRenderer;
|
||||
private RecordingCanvas mCanvas;
|
||||
private final boolean mIsWideColorGamut;
|
||||
|
||||
@@ -934,8 +935,13 @@ public class Surface implements Parcelable {
|
||||
mRenderNode.setClipToBounds(false);
|
||||
mRenderNode.setForceDarkAllowed(false);
|
||||
mIsWideColorGamut = isWideColorGamut;
|
||||
mHwuiRenderer = nHwuiCreate(mRenderNode.mNativeRenderNode, mNativeObject,
|
||||
isWideColorGamut);
|
||||
|
||||
mHardwareRenderer = new HardwareRenderer();
|
||||
mHardwareRenderer.setContentRoot(mRenderNode);
|
||||
mHardwareRenderer.setSurface(Surface.this, true);
|
||||
mHardwareRenderer.setWideGamut(isWideColorGamut);
|
||||
mHardwareRenderer.setLightSourceAlpha(0.0f, 0.0f);
|
||||
mHardwareRenderer.setLightSourceGeometry(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
Canvas lockCanvas(int width, int height) {
|
||||
@@ -953,27 +959,21 @@ public class Surface implements Parcelable {
|
||||
}
|
||||
mRenderNode.endRecording();
|
||||
mCanvas = null;
|
||||
nHwuiDraw(mHwuiRenderer);
|
||||
mHardwareRenderer.createRenderRequest()
|
||||
.setVsyncTime(System.nanoTime())
|
||||
.syncAndDraw();
|
||||
}
|
||||
|
||||
void updateSurface() {
|
||||
nHwuiSetSurface(mHwuiRenderer, mNativeObject);
|
||||
mHardwareRenderer.setSurface(Surface.this, true);
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
if (mHwuiRenderer != 0) {
|
||||
nHwuiDestroy(mHwuiRenderer);
|
||||
mHwuiRenderer = 0;
|
||||
}
|
||||
mHardwareRenderer.destroy();
|
||||
}
|
||||
|
||||
boolean isWideColorGamut() {
|
||||
return mIsWideColorGamut;
|
||||
}
|
||||
}
|
||||
|
||||
private static native long nHwuiCreate(long rootNode, long surface, boolean isWideColorGamut);
|
||||
private static native void nHwuiSetSurface(long renderer, long surface);
|
||||
private static native void nHwuiDraw(long renderer);
|
||||
private static native void nHwuiDestroy(long renderer);
|
||||
}
|
||||
|
||||
@@ -23,46 +23,66 @@
|
||||
#include <utils/Color.h>
|
||||
|
||||
#include <SkBitmap.h>
|
||||
#include <SkSurface.h>
|
||||
|
||||
using namespace android;
|
||||
|
||||
/*
|
||||
* Converts a buffer and dataspace into an SkBitmap only if the resulting bitmap can be treated as a
|
||||
* rendering destination for a Canvas. If the buffer is null or the format is one that we cannot
|
||||
* render into with a Canvas then false is returned and the outBitmap param is unmodified.
|
||||
*/
|
||||
static bool convert(const ANativeWindow_Buffer* buffer,
|
||||
int32_t /*android_dataspace_t*/ dataspace,
|
||||
SkBitmap* outBitmap) {
|
||||
if (buffer == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
sk_sp<SkColorSpace> cs(uirenderer::DataSpaceToColorSpace((android_dataspace)dataspace));
|
||||
SkImageInfo imageInfo = uirenderer::ANativeWindowToImageInfo(*buffer, cs);
|
||||
size_t rowBytes = buffer->stride * imageInfo.bytesPerPixel();
|
||||
|
||||
// If SkSurface::MakeRasterDirect fails then we should as well as we will not be able to
|
||||
// draw into the canvas.
|
||||
sk_sp<SkSurface> surface = SkSurface::MakeRasterDirect(imageInfo, buffer->bits, rowBytes);
|
||||
if (surface.get() != nullptr) {
|
||||
if (outBitmap) {
|
||||
outBitmap->setInfo(imageInfo, rowBytes);
|
||||
outBitmap->setPixels(buffer->bits);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ACanvas_isSupportedPixelFormat(int32_t bufferFormat) {
|
||||
ANativeWindow_Buffer buffer { 0, 0, 0, bufferFormat, nullptr, {0} };
|
||||
const SkColorType colorType = uirenderer::ANativeWindowToImageInfo(buffer, nullptr).colorType();
|
||||
return kUnknown_SkColorType != colorType;
|
||||
char pixels[8];
|
||||
ANativeWindow_Buffer buffer { 1, 1, 1, bufferFormat, pixels, {0} };
|
||||
return convert(&buffer, HAL_DATASPACE_UNKNOWN, nullptr);
|
||||
}
|
||||
|
||||
ACanvas* ACanvas_getNativeHandleFromJava(JNIEnv* env, jobject canvasObj) {
|
||||
return TypeCast::toACanvas(GraphicsJNI::getNativeCanvas(env, canvasObj));
|
||||
}
|
||||
|
||||
static SkBitmap convert(const ANativeWindow_Buffer* buffer,
|
||||
int32_t /*android_dataspace_t*/ dataspace) {
|
||||
SkBitmap bitmap;
|
||||
if (buffer != nullptr && buffer->width > 0 && buffer->height > 0) {
|
||||
sk_sp<SkColorSpace> cs(uirenderer::DataSpaceToColorSpace((android_dataspace)dataspace));
|
||||
SkImageInfo imageInfo = uirenderer::ANativeWindowToImageInfo(*buffer, cs);
|
||||
ssize_t rowBytes = buffer->stride * imageInfo.bytesPerPixel();
|
||||
bitmap.setInfo(imageInfo, rowBytes);
|
||||
bitmap.setPixels(buffer->bits);
|
||||
}
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
ACanvas* ACanvas_createCanvas(const ANativeWindow_Buffer* buffer,
|
||||
int32_t /*android_dataspace_t*/ dataspace) {
|
||||
return TypeCast::toACanvas(Canvas::create_canvas(convert(buffer, dataspace)));
|
||||
SkBitmap bitmap;
|
||||
bool isValidBuffer = convert(buffer, dataspace, &bitmap);
|
||||
return isValidBuffer ? TypeCast::toACanvas(Canvas::create_canvas(bitmap)) : nullptr;
|
||||
}
|
||||
|
||||
void ACanvas_destroyCanvas(ACanvas* canvas) {
|
||||
delete TypeCast::toCanvas(canvas);
|
||||
}
|
||||
|
||||
void ACanvas_setBuffer(ACanvas* canvas, const ANativeWindow_Buffer* buffer,
|
||||
bool ACanvas_setBuffer(ACanvas* canvas, const ANativeWindow_Buffer* buffer,
|
||||
int32_t /*android_dataspace_t*/ dataspace) {
|
||||
|
||||
|
||||
TypeCast::toCanvas(canvas)->setBitmap(convert(buffer, dataspace));
|
||||
SkBitmap bitmap;
|
||||
bool isValidBuffer = (buffer == nullptr) ? false : convert(buffer, dataspace, &bitmap);
|
||||
TypeCast::toCanvas(canvas)->setBitmap(bitmap);
|
||||
return isValidBuffer;
|
||||
}
|
||||
|
||||
void ACanvas_clipRect(ACanvas* canvas, const ARect* clipRect, bool /*doAA*/) {
|
||||
|
||||
@@ -42,7 +42,7 @@ ACanvas* ACanvas_getNativeHandleFromJava(JNIEnv* env, jobject canvas);
|
||||
/**
|
||||
* Creates a canvas that wraps the buffer
|
||||
*
|
||||
* @param buffer required
|
||||
* @param buffer is a required param. If no buffer is provided a nullptr will be returned.
|
||||
*/
|
||||
ACanvas* ACanvas_createCanvas(const ANativeWindow_Buffer* buffer,
|
||||
int32_t /*android_dataspace_t*/ dataspace);
|
||||
@@ -56,8 +56,11 @@ void ACanvas_destroyCanvas(ACanvas* canvas);
|
||||
* remain valid until the this method is called again with either another active
|
||||
* buffer or nullptr. If nullptr is given the canvas will release the previous buffer
|
||||
* and set an empty backing store.
|
||||
* @return A boolean value indicating whether or not the buffer was successfully set. If false the
|
||||
* method will behave as if nullptr were passed as the input buffer and the previous buffer
|
||||
* will still be released.
|
||||
*/
|
||||
void ACanvas_setBuffer(ACanvas* canvas, const ANativeWindow_Buffer* buffer,
|
||||
bool ACanvas_setBuffer(ACanvas* canvas, const ANativeWindow_Buffer* buffer,
|
||||
int32_t /*android_dataspace_t*/ dataspace);
|
||||
|
||||
/**
|
||||
@@ -110,9 +113,9 @@ namespace graphics {
|
||||
}
|
||||
}
|
||||
|
||||
void setBuffer(const ANativeWindow_Buffer* buffer,
|
||||
bool setBuffer(const ANativeWindow_Buffer* buffer,
|
||||
int32_t /*android_dataspace_t*/ dataspace) {
|
||||
ACanvas_setBuffer(mCanvas, buffer, dataspace);
|
||||
return ACanvas_setBuffer(mCanvas, buffer, dataspace);
|
||||
}
|
||||
|
||||
void clipRect(const ARect& clipRect, bool doAntiAlias = false) {
|
||||
|
||||
@@ -45,11 +45,6 @@
|
||||
|
||||
#include <nativehelper/ScopedUtfChars.h>
|
||||
|
||||
#include <AnimationContext.h>
|
||||
#include <FrameInfo.h>
|
||||
#include <RenderNode.h>
|
||||
#include <renderthread/RenderProxy.h>
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
namespace android {
|
||||
@@ -189,21 +184,6 @@ static jboolean nativeIsConsumerRunningBehind(JNIEnv* env, jclass clazz, jlong n
|
||||
return value;
|
||||
}
|
||||
|
||||
static inline SkColorType convertPixelFormat(PixelFormat format) {
|
||||
/* note: if PIXEL_FORMAT_RGBX_8888 means that all alpha bytes are 0xFF, then
|
||||
we can map to kN32_SkColorType, and optionally call
|
||||
bitmap.setAlphaType(kOpaque_SkAlphaType) on the resulting SkBitmap
|
||||
(as an accelerator)
|
||||
*/
|
||||
switch (format) {
|
||||
case PIXEL_FORMAT_RGBX_8888: return kN32_SkColorType;
|
||||
case PIXEL_FORMAT_RGBA_8888: return kN32_SkColorType;
|
||||
case PIXEL_FORMAT_RGBA_FP16: return kRGBA_F16_SkColorType;
|
||||
case PIXEL_FORMAT_RGB_565: return kRGB_565_SkColorType;
|
||||
default: return kUnknown_SkColorType;
|
||||
}
|
||||
}
|
||||
|
||||
static jlong nativeLockCanvas(JNIEnv* env, jclass clazz,
|
||||
jlong nativeObject, jobject canvasObj, jobject dirtyRectObj) {
|
||||
sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject));
|
||||
@@ -213,7 +193,7 @@ static jlong nativeLockCanvas(JNIEnv* env, jclass clazz,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (convertPixelFormat(ANativeWindow_getFormat(surface.get())) == kUnknown_SkColorType) {
|
||||
if (!ACanvas_isSupportedPixelFormat(ANativeWindow_getFormat(surface.get()))) {
|
||||
native_window_set_buffers_format(surface.get(), PIXEL_FORMAT_RGBA_8888);
|
||||
}
|
||||
|
||||
@@ -433,62 +413,8 @@ static jint nativeSetAutoRefreshEnabled(JNIEnv* env, jclass clazz, jlong nativeO
|
||||
return anw->perform(surface, NATIVE_WINDOW_SET_AUTO_REFRESH, int(enabled));
|
||||
}
|
||||
|
||||
namespace uirenderer {
|
||||
|
||||
using namespace android::uirenderer::renderthread;
|
||||
|
||||
class ContextFactory : public IContextFactory {
|
||||
public:
|
||||
virtual AnimationContext* createAnimationContext(renderthread::TimeLord& clock) {
|
||||
return new AnimationContext(clock);
|
||||
}
|
||||
};
|
||||
|
||||
static jlong create(JNIEnv* env, jclass clazz, jlong rootNodePtr, jlong surfacePtr,
|
||||
jboolean isWideColorGamut) {
|
||||
RenderNode* rootNode = reinterpret_cast<RenderNode*>(rootNodePtr);
|
||||
sp<Surface> surface(reinterpret_cast<Surface*>(surfacePtr));
|
||||
ContextFactory factory;
|
||||
RenderProxy* proxy = new RenderProxy(false, rootNode, &factory);
|
||||
proxy->loadSystemProperties();
|
||||
if (isWideColorGamut) {
|
||||
proxy->setWideGamut(true);
|
||||
}
|
||||
proxy->setSwapBehavior(SwapBehavior::kSwap_discardBuffer);
|
||||
proxy->setSurface(surface);
|
||||
// Shadows can't be used via this interface, so just set the light source
|
||||
// to all 0s.
|
||||
proxy->setLightAlpha(0, 0);
|
||||
proxy->setLightGeometry((Vector3){0, 0, 0}, 0);
|
||||
return (jlong) proxy;
|
||||
}
|
||||
|
||||
static void setSurface(JNIEnv* env, jclass clazz, jlong rendererPtr, jlong surfacePtr) {
|
||||
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(rendererPtr);
|
||||
sp<Surface> surface(reinterpret_cast<Surface*>(surfacePtr));
|
||||
proxy->setSurface(surface);
|
||||
}
|
||||
|
||||
static void draw(JNIEnv* env, jclass clazz, jlong rendererPtr) {
|
||||
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(rendererPtr);
|
||||
nsecs_t vsync = systemTime(SYSTEM_TIME_MONOTONIC);
|
||||
UiFrameInfoBuilder(proxy->frameInfo())
|
||||
.setVsync(vsync, vsync)
|
||||
.addFlag(FrameInfoFlags::SurfaceCanvas);
|
||||
proxy->syncAndDrawFrame();
|
||||
}
|
||||
|
||||
static void destroy(JNIEnv* env, jclass clazz, jlong rendererPtr) {
|
||||
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(rendererPtr);
|
||||
delete proxy;
|
||||
}
|
||||
|
||||
} // uirenderer
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
namespace hwui = android::uirenderer;
|
||||
|
||||
static const JNINativeMethod gSurfaceMethods[] = {
|
||||
{"nativeCreateFromSurfaceTexture", "(Landroid/graphics/SurfaceTexture;)J",
|
||||
(void*)nativeCreateFromSurfaceTexture },
|
||||
@@ -521,12 +447,6 @@ static const JNINativeMethod gSurfaceMethods[] = {
|
||||
(void*)nativeAttachAndQueueBufferWithColorSpace},
|
||||
{"nativeSetSharedBufferModeEnabled", "(JZ)I", (void*)nativeSetSharedBufferModeEnabled},
|
||||
{"nativeSetAutoRefreshEnabled", "(JZ)I", (void*)nativeSetAutoRefreshEnabled},
|
||||
|
||||
// HWUI context
|
||||
{"nHwuiCreate", "(JJZ)J", (void*) hwui::create },
|
||||
{"nHwuiSetSurface", "(JJ)V", (void*) hwui::setSurface },
|
||||
{"nHwuiDraw", "(J)V", (void*) hwui::draw },
|
||||
{"nHwuiDestroy", "(J)V", (void*) hwui::destroy },
|
||||
};
|
||||
|
||||
int register_android_view_Surface(JNIEnv* env)
|
||||
|
||||
@@ -174,12 +174,15 @@ static void android_view_ThreadedRenderer_setName(JNIEnv* env, jobject clazz,
|
||||
}
|
||||
|
||||
static void android_view_ThreadedRenderer_setSurface(JNIEnv* env, jobject clazz,
|
||||
jlong proxyPtr, jobject jsurface) {
|
||||
jlong proxyPtr, jobject jsurface, jboolean discardBuffer) {
|
||||
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
|
||||
sp<Surface> surface;
|
||||
if (jsurface) {
|
||||
surface = android_view_Surface_getSurface(env, jsurface);
|
||||
}
|
||||
if (discardBuffer) {
|
||||
proxy->setSwapBehavior(SwapBehavior::kSwap_discardBuffer);
|
||||
}
|
||||
proxy->setSurface(surface);
|
||||
}
|
||||
|
||||
@@ -632,7 +635,7 @@ static const JNINativeMethod gMethods[] = {
|
||||
{ "nDeleteProxy", "(J)V", (void*) android_view_ThreadedRenderer_deleteProxy },
|
||||
{ "nLoadSystemProperties", "(J)Z", (void*) android_view_ThreadedRenderer_loadSystemProperties },
|
||||
{ "nSetName", "(JLjava/lang/String;)V", (void*) android_view_ThreadedRenderer_setName },
|
||||
{ "nSetSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_setSurface },
|
||||
{ "nSetSurface", "(JLandroid/view/Surface;Z)V", (void*) android_view_ThreadedRenderer_setSurface },
|
||||
{ "nPause", "(J)Z", (void*) android_view_ThreadedRenderer_pause },
|
||||
{ "nSetStopped", "(JZ)V", (void*) android_view_ThreadedRenderer_setStopped },
|
||||
{ "nSetLightAlpha", "(JFF)V", (void*) android_view_ThreadedRenderer_setLightAlpha },
|
||||
|
||||
@@ -286,10 +286,24 @@ public class HardwareRenderer {
|
||||
* non-null then {@link Surface#isValid()} must be true.
|
||||
*/
|
||||
public void setSurface(@Nullable Surface surface) {
|
||||
setSurface(surface, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* See {@link #setSurface(Surface)}
|
||||
*
|
||||
* @hide
|
||||
* @param discardBuffer determines whether the surface will attempt to preserve its contents
|
||||
* between frames. If set to true the renderer will attempt to preserve
|
||||
* the contents of the buffer between frames if the implementation allows
|
||||
* it. If set to false no attempt will be made to preserve the buffer's
|
||||
* contents between frames.
|
||||
*/
|
||||
public void setSurface(@Nullable Surface surface, boolean discardBuffer) {
|
||||
if (surface != null && !surface.isValid()) {
|
||||
throw new IllegalArgumentException("Surface is invalid. surface.isValid() == false.");
|
||||
}
|
||||
nSetSurface(mNativeProxy, surface);
|
||||
nSetSurface(mNativeProxy, surface, discardBuffer);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1084,7 +1098,7 @@ public class HardwareRenderer {
|
||||
|
||||
private static native void nSetName(long nativeProxy, String name);
|
||||
|
||||
private static native void nSetSurface(long nativeProxy, Surface window);
|
||||
private static native void nSetSurface(long nativeProxy, Surface window, boolean discardBuffer);
|
||||
|
||||
private static native boolean nPause(long nativeProxy);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user