Merge "Post to all existing and non-existing clients of the buffer in BufferHubBuffer"
diff --git a/cmds/servicemanager/binder.c b/cmds/servicemanager/binder.c
index fade8cf..a2b4da2 100644
--- a/cmds/servicemanager/binder.c
+++ b/cmds/servicemanager/binder.c
@@ -146,7 +146,21 @@
int binder_become_context_manager(struct binder_state *bs)
{
- return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
+ struct flat_binder_object obj;
+ memset(&obj, 0, sizeof(obj));
+ obj.flags = FLAT_BINDER_FLAG_TXN_SECURITY_CTX;
+
+ int result = ioctl(bs->fd, BINDER_SET_CONTEXT_MGR_EXT, &obj);
+
+ // fallback to original method
+ if (result != 0) {
+#ifndef VENDORSERVICEMANAGER
+ android_errorWriteLog(0x534e4554, "121035042");
+#endif
+
+ result = ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
+ }
+ return result;
}
int binder_write(struct binder_state *bs, void *data, size_t len)
@@ -240,13 +254,28 @@
#endif
ptr += sizeof(struct binder_ptr_cookie);
break;
+ case BR_TRANSACTION_SEC_CTX:
case BR_TRANSACTION: {
- struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr;
- if ((end - ptr) < sizeof(*txn)) {
- ALOGE("parse: txn too small!\n");
- return -1;
+ struct binder_transaction_data_secctx txn;
+ if (cmd == BR_TRANSACTION_SEC_CTX) {
+ if ((end - ptr) < sizeof(struct binder_transaction_data_secctx)) {
+ ALOGE("parse: txn too small (binder_transaction_data_secctx)!\n");
+ return -1;
+ }
+ memcpy(&txn, (void*) ptr, sizeof(struct binder_transaction_data_secctx));
+ ptr += sizeof(struct binder_transaction_data_secctx);
+ } else /* BR_TRANSACTION */ {
+ if ((end - ptr) < sizeof(struct binder_transaction_data)) {
+ ALOGE("parse: txn too small (binder_transaction_data)!\n");
+ return -1;
+ }
+ memcpy(&txn.transaction_data, (void*) ptr, sizeof(struct binder_transaction_data));
+ ptr += sizeof(struct binder_transaction_data);
+
+ txn.secctx = 0;
}
- binder_dump_txn(txn);
+
+ binder_dump_txn(&txn.transaction_data);
if (func) {
unsigned rdata[256/4];
struct binder_io msg;
@@ -254,15 +283,14 @@
int res;
bio_init(&reply, rdata, sizeof(rdata), 4);
- bio_init_from_txn(&msg, txn);
- res = func(bs, txn, &msg, &reply);
- if (txn->flags & TF_ONE_WAY) {
- binder_free_buffer(bs, txn->data.ptr.buffer);
+ bio_init_from_txn(&msg, &txn.transaction_data);
+ res = func(bs, &txn, &msg, &reply);
+ if (txn.transaction_data.flags & TF_ONE_WAY) {
+ binder_free_buffer(bs, txn.transaction_data.data.ptr.buffer);
} else {
- binder_send_reply(bs, &reply, txn->data.ptr.buffer, res);
+ binder_send_reply(bs, &reply, txn.transaction_data.data.ptr.buffer, res);
}
}
- ptr += sizeof(*txn);
break;
}
case BR_REPLY: {
diff --git a/cmds/servicemanager/binder.h b/cmds/servicemanager/binder.h
index c95b33f..70be3b4 100644
--- a/cmds/servicemanager/binder.h
+++ b/cmds/servicemanager/binder.h
@@ -5,7 +5,8 @@
#define _BINDER_H_
#include <sys/ioctl.h>
-#include <linux/android/binder.h>
+
+#include "binder_kernel.h"
struct binder_state;
@@ -42,7 +43,7 @@
};
typedef int (*binder_handler)(struct binder_state *bs,
- struct binder_transaction_data *txn,
+ struct binder_transaction_data_secctx *txn,
struct binder_io *msg,
struct binder_io *reply);
diff --git a/cmds/servicemanager/binder_kernel.h b/cmds/servicemanager/binder_kernel.h
new file mode 100644
index 0000000..19fd773
--- /dev/null
+++ b/cmds/servicemanager/binder_kernel.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_BINDER_KERNEL_H
+#define ANDROID_BINDER_KERNEL_H
+
+#include <linux/android/binder.h>
+
+/**
+ * This file exists because the uapi kernel headers in bionic are built
+ * from upstream kernel headers only, and not all of the hwbinder kernel changes
+ * have made it upstream yet. Therefore, the modifications to the
+ * binder header are added locally in this file.
+ */
+
+enum {
+ FLAT_BINDER_FLAG_TXN_SECURITY_CTX = 0x1000,
+};
+
+#define BINDER_SET_CONTEXT_MGR_EXT _IOW('b', 13, struct flat_binder_object)
+
+struct binder_transaction_data_secctx {
+ struct binder_transaction_data transaction_data;
+ binder_uintptr_t secctx;
+};
+
+enum {
+ BR_TRANSACTION_SEC_CTX = _IOR('r', 2,
+ struct binder_transaction_data_secctx),
+};
+
+
+#endif // ANDROID_BINDER_KERNEL_H
diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c
index 79cd6b5..ca004e9 100644
--- a/cmds/servicemanager/service_manager.c
+++ b/cmds/servicemanager/service_manager.c
@@ -61,14 +61,14 @@
static char *service_manager_context;
static struct selabel_handle* sehandle;
-static bool check_mac_perms(pid_t spid, uid_t uid, const char *tctx, const char *perm, const char *name)
+static bool check_mac_perms(pid_t spid, const char* sid, uid_t uid, const char *tctx, const char *perm, const char *name)
{
- char *sctx = NULL;
+ char *lookup_sid = NULL;
const char *class = "service_manager";
bool allowed;
struct audit_data ad;
- if (getpidcon(spid, &sctx) < 0) {
+ if (sid == NULL && getpidcon(spid, &lookup_sid) < 0) {
ALOGE("SELinux: getpidcon(pid=%d) failed to retrieve pid context.\n", spid);
return false;
}
@@ -77,19 +77,25 @@
ad.uid = uid;
ad.name = name;
- int result = selinux_check_access(sctx, tctx, class, perm, (void *) &ad);
+#ifndef VENDORSERVICEMANAGER
+ if (sid == NULL) {
+ android_errorWriteLog(0x534e4554, "121035042");
+ }
+#endif
+
+ int result = selinux_check_access(sid ? sid : lookup_sid, tctx, class, perm, (void *) &ad);
allowed = (result == 0);
- freecon(sctx);
+ freecon(lookup_sid);
return allowed;
}
-static bool check_mac_perms_from_getcon(pid_t spid, uid_t uid, const char *perm)
+static bool check_mac_perms_from_getcon(pid_t spid, const char* sid, uid_t uid, const char *perm)
{
- return check_mac_perms(spid, uid, service_manager_context, perm, NULL);
+ return check_mac_perms(spid, sid, uid, service_manager_context, perm, NULL);
}
-static bool check_mac_perms_from_lookup(pid_t spid, uid_t uid, const char *perm, const char *name)
+static bool check_mac_perms_from_lookup(pid_t spid, const char* sid, uid_t uid, const char *perm, const char *name)
{
bool allowed;
char *tctx = NULL;
@@ -104,12 +110,12 @@
return false;
}
- allowed = check_mac_perms(spid, uid, tctx, perm, name);
+ allowed = check_mac_perms(spid, sid, uid, tctx, perm, name);
freecon(tctx);
return allowed;
}
-static int svc_can_register(const uint16_t *name, size_t name_len, pid_t spid, uid_t uid)
+static int svc_can_register(const uint16_t *name, size_t name_len, pid_t spid, const char* sid, uid_t uid)
{
const char *perm = "add";
@@ -117,19 +123,19 @@
return 0; /* Don't allow apps to register services */
}
- return check_mac_perms_from_lookup(spid, uid, perm, str8(name, name_len)) ? 1 : 0;
+ return check_mac_perms_from_lookup(spid, sid, uid, perm, str8(name, name_len)) ? 1 : 0;
}
-static int svc_can_list(pid_t spid, uid_t uid)
+static int svc_can_list(pid_t spid, const char* sid, uid_t uid)
{
const char *perm = "list";
- return check_mac_perms_from_getcon(spid, uid, perm) ? 1 : 0;
+ return check_mac_perms_from_getcon(spid, sid, uid, perm) ? 1 : 0;
}
-static int svc_can_find(const uint16_t *name, size_t name_len, pid_t spid, uid_t uid)
+static int svc_can_find(const uint16_t *name, size_t name_len, pid_t spid, const char* sid, uid_t uid)
{
const char *perm = "find";
- return check_mac_perms_from_lookup(spid, uid, perm, str8(name, name_len)) ? 1 : 0;
+ return check_mac_perms_from_lookup(spid, sid, uid, perm, str8(name, name_len)) ? 1 : 0;
}
struct svcinfo
@@ -175,7 +181,7 @@
};
-uint32_t do_find_service(const uint16_t *s, size_t len, uid_t uid, pid_t spid)
+uint32_t do_find_service(const uint16_t *s, size_t len, uid_t uid, pid_t spid, const char* sid)
{
struct svcinfo *si = find_svc(s, len);
@@ -192,7 +198,7 @@
}
}
- if (!svc_can_find(s, len, spid, uid)) {
+ if (!svc_can_find(s, len, spid, sid, uid)) {
return 0;
}
@@ -200,7 +206,7 @@
}
int do_add_service(struct binder_state *bs, const uint16_t *s, size_t len, uint32_t handle,
- uid_t uid, int allow_isolated, uint32_t dumpsys_priority, pid_t spid) {
+ uid_t uid, int allow_isolated, uint32_t dumpsys_priority, pid_t spid, const char* sid) {
struct svcinfo *si;
//ALOGI("add_service('%s',%x,%s) uid=%d\n", str8(s, len), handle,
@@ -209,7 +215,7 @@
if (!handle || (len == 0) || (len > 127))
return -1;
- if (!svc_can_register(s, len, spid, uid)) {
+ if (!svc_can_register(s, len, spid, sid, uid)) {
ALOGE("add_service('%s',%x) uid=%d - PERMISSION DENIED\n",
str8(s, len), handle, uid);
return -1;
@@ -248,7 +254,7 @@
}
int svcmgr_handler(struct binder_state *bs,
- struct binder_transaction_data *txn,
+ struct binder_transaction_data_secctx *txn_secctx,
struct binder_io *msg,
struct binder_io *reply)
{
@@ -260,6 +266,8 @@
int allow_isolated;
uint32_t dumpsys_priority;
+ struct binder_transaction_data *txn = &txn_secctx->transaction_data;
+
//ALOGI("target=%p code=%d pid=%d uid=%d\n",
// (void*) txn->target.ptr, txn->code, txn->sender_pid, txn->sender_euid);
@@ -305,7 +313,8 @@
if (s == NULL) {
return -1;
}
- handle = do_find_service(s, len, txn->sender_euid, txn->sender_pid);
+ handle = do_find_service(s, len, txn->sender_euid, txn->sender_pid,
+ (const char*) txn_secctx->secctx);
if (!handle)
break;
bio_put_ref(reply, handle);
@@ -320,7 +329,7 @@
allow_isolated = bio_get_uint32(msg) ? 1 : 0;
dumpsys_priority = bio_get_uint32(msg);
if (do_add_service(bs, s, len, handle, txn->sender_euid, allow_isolated, dumpsys_priority,
- txn->sender_pid))
+ txn->sender_pid, (const char*) txn_secctx->secctx))
return -1;
break;
@@ -328,7 +337,7 @@
uint32_t n = bio_get_uint32(msg);
uint32_t req_dumpsys_priority = bio_get_uint32(msg);
- if (!svc_can_list(txn->sender_pid, txn->sender_euid)) {
+ if (!svc_can_list(txn->sender_pid, (const char*) txn_secctx->secctx, txn->sender_euid)) {
ALOGE("list_service() uid=%d - PERMISSION DENIED\n",
txn->sender_euid);
return -1;
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index d0a0ac8..94a6650 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -626,6 +626,25 @@
return NO_ERROR;
}
+FloatRect GLESRenderEngine::setupLayerCropping(const LayerSettings& layer, Mesh& mesh) {
+ // Translate win by the rounded corners rect coordinates, to have all values in
+ // layer coordinate space.
+ FloatRect cropWin = layer.geometry.boundaries;
+ const FloatRect& roundedCornersCrop = layer.geometry.roundedCornersCrop;
+ cropWin.left -= roundedCornersCrop.left;
+ cropWin.right -= roundedCornersCrop.left;
+ cropWin.top -= roundedCornersCrop.top;
+ cropWin.bottom -= roundedCornersCrop.top;
+ Mesh::VertexArray<vec2> cropCoords(mesh.getCropCoordArray<vec2>());
+ cropCoords[0] = vec2(cropWin.left, cropWin.top);
+ cropCoords[1] = vec2(cropWin.left, cropWin.top + cropWin.getHeight());
+ cropCoords[2] = vec2(cropWin.right, cropWin.top + cropWin.getHeight());
+ cropCoords[3] = vec2(cropWin.right, cropWin.top);
+
+ setupCornerRadiusCropSize(roundedCornersCrop.getWidth(), roundedCornersCrop.getHeight());
+ return cropWin;
+}
+
status_t GLESRenderEngine::bindFrameBuffer(Framebuffer* framebuffer) {
GLFramebuffer* glFramebuffer = static_cast<GLFramebuffer*>(framebuffer);
EGLImageKHR eglImage = glFramebuffer->getEGLImage();
@@ -714,6 +733,10 @@
setDisplayMaxLuminance(display.maxLuminance);
mat4 projectionMatrix = mState.projectionMatrix * display.globalTransform;
+ mState.projectionMatrix = projectionMatrix;
+ if (!display.clearRegion.isEmpty()) {
+ fillRegionWithColor(display.clearRegion, 0.0, 0.0, 0.0, 1.0);
+ }
Mesh mesh(Mesh::TRIANGLE_FAN, 4, 2, 2);
for (auto layer : layers) {
@@ -726,6 +749,7 @@
position[2] = vec2(bounds.right, bounds.bottom);
position[3] = vec2(bounds.right, bounds.top);
+ setupLayerCropping(layer, mesh);
setColorTransform(display.colorTransform * layer.colorTransform);
bool usePremultipliedAlpha = true;
@@ -760,7 +784,7 @@
// Buffer sources will have a black solid color ignored in the shader,
// so in that scenario the solid color passed here is arbitrary.
setupLayerBlending(usePremultipliedAlpha, layer.source.buffer.isOpaque, disableTexture,
- color, /*cornerRadius=*/0.0);
+ color, layer.geometry.roundedCornersRadius);
setSourceDataSpace(layer.sourceDataspace);
drawMesh(mesh);
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index 2af2aed..511a784 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -128,6 +128,9 @@
// defined by the clip.
void setViewportAndProjection(Rect viewport, Rect clip);
status_t bindExternalTextureBuffer(uint32_t texName, sp<GraphicBuffer> buffer, sp<Fence> fence);
+ // Computes the cropping window for the layer and sets up cropping
+ // coordinates for the mesh.
+ FloatRect setupLayerCropping(const LayerSettings& layer, Mesh& mesh);
EGLDisplay mEGLDisplay;
EGLConfig mEGLConfig;
diff --git a/libs/renderengine/include/renderengine/DisplaySettings.h b/libs/renderengine/include/renderengine/DisplaySettings.h
index 0c92353..af8de23 100644
--- a/libs/renderengine/include/renderengine/DisplaySettings.h
+++ b/libs/renderengine/include/renderengine/DisplaySettings.h
@@ -51,9 +51,10 @@
// to the output dataspace.
mat4 colorTransform = mat4();
- // Region that will be cleared to (0, 0, 0, 0) prior to rendering.
- // clearRegion will first be transformed by globalTransform so that it will
- // be in the same coordinate space as the rendered layers.
+ // Region that will be cleared to (0, 0, 0, 1) prior to rendering.
+ // RenderEngine will transform the clearRegion passed in here, by
+ // globalTransform, so that it will be in the same coordinate space as the
+ // rendered layers.
Region clearRegion = Region::INVALID_REGION;
};
diff --git a/libs/renderengine/include/renderengine/LayerSettings.h b/libs/renderengine/include/renderengine/LayerSettings.h
index a37a163..4d53205 100644
--- a/libs/renderengine/include/renderengine/LayerSettings.h
+++ b/libs/renderengine/include/renderengine/LayerSettings.h
@@ -69,6 +69,20 @@
// Transform matrix to apply to mesh coordinates.
mat4 positionTransform = mat4();
+
+ // Radius of rounded corners, if greater than 0. Otherwise, this layer's
+ // corners are not rounded.
+ // Having corner radius will force GPU composition on the layer and its children, drawing it
+ // with a special shader. The shader will receive the radius and the crop rectangle as input,
+ // modifying the opacity of the destination texture, multiplying it by a number between 0 and 1.
+ // We query Layer#getRoundedCornerState() to retrieve the radius as well as the rounded crop
+ // rectangle to figure out how to apply the radius for this layer. The crop rectangle will be
+ // in local layer coordinate space, so we have to take the layer transform into account when
+ // walking up the tree.
+ float roundedCornersRadius = 0.0;
+
+ // Rectangle within which corners will be rounded.
+ FloatRect roundedCornersCrop = FloatRect();
};
// Descriptor of the source pixels for this layer.
@@ -94,11 +108,11 @@
half alpha = half(0.0);
// Color space describing how the source pixels should be interpreted.
- ui::Dataspace sourceDataspace;
+ ui::Dataspace sourceDataspace = ui::Dataspace::UNKNOWN;
// Additional layer-specific color transform to be applied before the global
// transform.
- mat4 colorTransform;
+ mat4 colorTransform = mat4();
};
} // namespace renderengine
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index e43ee37..bef25a8 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -172,6 +172,12 @@
template <typename SourceVariant>
void fillBufferColorTransform();
+ template <typename SourceVariant>
+ void fillRedBufferWithRoundedCorners();
+
+ template <typename SourceVariant>
+ void fillBufferWithRoundedCorners();
+
void fillRedBufferTextureTransform();
void fillBufferTextureTransform();
@@ -184,6 +190,12 @@
void fillBufferWithoutPremultiplyAlpha();
+ void fillGreenColorBufferThenClearRegion();
+
+ void clearLeftRegion();
+
+ void fillBufferThenClearRegion();
+
// Dumb hack to get aroud the fact that tear-down for renderengine isn't
// well defined right now, so we can't create multiple instances
static std::unique_ptr<renderengine::RenderEngine> sRE;
@@ -495,6 +507,42 @@
expectBufferColor(fullscreenRect(), 191, 0, 0, 255);
}
+template <typename SourceVariant>
+void RenderEngineTest::fillRedBufferWithRoundedCorners() {
+ renderengine::DisplaySettings settings;
+ settings.physicalDisplay = fullscreenRect();
+ settings.clip = fullscreenRect();
+
+ std::vector<renderengine::LayerSettings> layers;
+
+ renderengine::LayerSettings layer;
+ layer.geometry.boundaries = fullscreenRect().toFloatRect();
+ layer.geometry.roundedCornersRadius = 5.0f;
+ layer.geometry.roundedCornersCrop = fullscreenRect().toFloatRect();
+ SourceVariant::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
+ layer.alpha = 1.0f;
+
+ layers.push_back(layer);
+
+ invokeDraw(settings, layers, mBuffer);
+}
+
+template <typename SourceVariant>
+void RenderEngineTest::fillBufferWithRoundedCorners() {
+ fillRedBufferWithRoundedCorners<SourceVariant>();
+ // Corners should be ignored...
+ expectBufferColor(Rect(0, 0, 1, 1), 0, 0, 0, 0);
+ expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH - 1, 0, DEFAULT_DISPLAY_WIDTH, 1), 0, 0, 0, 0);
+ expectBufferColor(Rect(0, DEFAULT_DISPLAY_HEIGHT - 1, 1, DEFAULT_DISPLAY_HEIGHT), 0, 0, 0, 0);
+ expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH - 1, DEFAULT_DISPLAY_HEIGHT - 1,
+ DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+ 0, 0, 0, 0);
+ // ...And the non-rounded portion should be red.
+ // Other pixels may be anti-aliased, so let's not check those.
+ expectBufferColor(Rect(5, 5, DEFAULT_DISPLAY_WIDTH - 5, DEFAULT_DISPLAY_HEIGHT - 5), 255, 0, 0,
+ 255);
+}
+
void RenderEngineTest::fillRedBufferTextureTransform() {
renderengine::DisplaySettings settings;
settings.physicalDisplay = fullscreenRect();
@@ -623,6 +671,30 @@
expectBufferColor(fullscreenRect(), 128, 0, 0, 64, 1);
}
+void RenderEngineTest::clearLeftRegion() {
+ renderengine::DisplaySettings settings;
+ settings.physicalDisplay = fullscreenRect();
+ // Here logical space is 4x4
+ settings.clip = Rect(4, 4);
+ settings.globalTransform = mat4::scale(vec4(2, 4, 0, 1));
+ settings.clearRegion = Region(Rect(1, 1));
+ std::vector<renderengine::LayerSettings> layers;
+ // dummy layer, without bounds should not render anything
+ renderengine::LayerSettings layer;
+ layers.push_back(layer);
+ invokeDraw(settings, layers, mBuffer);
+}
+
+void RenderEngineTest::fillBufferThenClearRegion() {
+ fillGreenBuffer<ColorSourceVariant>();
+ // Reuse mBuffer
+ clearLeftRegion();
+ expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT), 0, 0, 0, 255);
+ expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 2, 0, DEFAULT_DISPLAY_WIDTH,
+ DEFAULT_DISPLAY_HEIGHT),
+ 0, 255, 0, 255);
+}
+
TEST_F(RenderEngineTest, drawLayers_noLayersToDraw) {
drawEmptyLayers();
}
@@ -671,6 +743,10 @@
fillBufferLayerTransform<ColorSourceVariant>();
}
+TEST_F(RenderEngineTest, drawLayers_fillBufferRoundedCorners_colorSource) {
+ fillBufferWithRoundedCorners<ColorSourceVariant>();
+}
+
TEST_F(RenderEngineTest, drawLayers_fillRedBuffer_opaqueBufferSource) {
fillRedBuffer<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
@@ -715,6 +791,10 @@
fillBufferLayerTransform<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
+TEST_F(RenderEngineTest, drawLayers_fillBufferRoundedCorners_opaqueBufferSource) {
+ fillBufferWithRoundedCorners<BufferSourceVariant<ForceOpaqueBufferVariant>>();
+}
+
TEST_F(RenderEngineTest, drawLayers_fillRedBuffer_bufferSource) {
fillRedBuffer<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
@@ -759,6 +839,10 @@
fillBufferLayerTransform<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
+TEST_F(RenderEngineTest, drawLayers_fillBufferRoundedCorners_bufferSource) {
+ fillBufferWithRoundedCorners<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
+}
+
TEST_F(RenderEngineTest, drawLayers_fillBufferTextureTransform) {
fillBufferTextureTransform();
}
@@ -771,4 +855,8 @@
fillBufferWithoutPremultiplyAlpha();
}
+TEST_F(RenderEngineTest, drawLayers_fillBufferThenClearRegion) {
+ fillBufferThenClearRegion();
+}
+
} // namespace android
diff --git a/libs/vr/libbufferhub/buffer_hub-test.cpp b/libs/vr/libbufferhub/buffer_hub-test.cpp
index 1359f4c..487a604 100644
--- a/libs/vr/libbufferhub/buffer_hub-test.cpp
+++ b/libs/vr/libbufferhub/buffer_hub-test.cpp
@@ -361,9 +361,11 @@
ASSERT_TRUE(p.get() != nullptr);
ASSERT_EQ(0, p->GainAsync());
ASSERT_EQ(0, p->Post(LocalHandle()));
- // Producer state bit is in released state after post. The overall state of
- // the buffer is also released because there is no consumer of this buffer.
- ASSERT_TRUE(IsBufferReleased(p->buffer_state()));
+ // Producer state bit is in released state after post, other clients shall be
+ // in posted state although there is no consumer of this buffer yet.
+ ASSERT_TRUE(IsClientReleased(p->buffer_state(), p->client_state_mask()));
+ ASSERT_FALSE(IsBufferReleased(p->buffer_state()));
+ ASSERT_TRUE(AnyClientPosted(p->buffer_state()));
// Gain in released state should succeed.
LocalHandle invalid_fence;
@@ -450,27 +452,17 @@
LocalHandle invalid_fence;
// Post the gained buffer before any consumer gets created.
- // The buffer should be in released state because it is not expected to be
- // read by any clients.
EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence));
- EXPECT_TRUE(IsBufferReleased(p->buffer_state()));
+ EXPECT_FALSE(IsBufferReleased(p->buffer_state()));
EXPECT_EQ(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
- // Newly created consumer will not be signalled for the posted buffer before
- // its creation. It cannot acquire the buffer immediately.
+ // Newly created consumer will be signalled for the posted buffer although it
+ // is created after producer posting.
std::unique_ptr<ConsumerBuffer> c =
ConsumerBuffer::Import(p->CreateConsumer());
ASSERT_TRUE(c.get() != nullptr);
- EXPECT_FALSE(IsClientPosted(c->buffer_state(), c->client_state_mask()));
- EXPECT_EQ(-EBUSY, c->AcquireAsync(&metadata, &invalid_fence));
-
- // Producer should be able to gain back and post the buffer
- EXPECT_EQ(0, p->GainAsync());
- EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence));
-
- // Consumer should be able to pick up the buffer this time.
+ EXPECT_TRUE(IsClientPosted(c->buffer_state(), c->client_state_mask()));
EXPECT_EQ(0, c->AcquireAsync(&metadata, &invalid_fence));
- EXPECT_TRUE(IsClientAcquired(c->buffer_state(), c->client_state_mask()));
}
TEST_F(LibBufferHubTest, TestCreateConsumerWhenBufferReleased) {
diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h
index 440a59d..889763a 100644
--- a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h
+++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h
@@ -94,6 +94,12 @@
return buffer_state_->load(std::memory_order_acquire);
};
+ // Returns whether the buffer is already released by all current clients.
+ bool is_released() {
+ return (buffer_state() &
+ active_clients_bit_mask_->load(std::memory_order_acquire)) == 0;
+ }
+
// A state mask which is unique to a buffer hub client among all its siblings
// sharing the same concrete graphic buffer.
uint32_t client_state_mask() const { return client_state_mask_; }
diff --git a/libs/vr/libbufferhub/producer_buffer.cpp b/libs/vr/libbufferhub/producer_buffer.cpp
index 5274bf2..edfdddf 100644
--- a/libs/vr/libbufferhub/producer_buffer.cpp
+++ b/libs/vr/libbufferhub/producer_buffer.cpp
@@ -89,13 +89,10 @@
return -EBUSY;
}
- // Set the producer client buffer state to released, other clients' buffer
- // state to posted.
- uint32_t current_active_clients_bit_mask =
- active_clients_bit_mask_->load(std::memory_order_acquire);
- uint32_t updated_buffer_state = current_active_clients_bit_mask &
- (~client_state_mask()) &
- BufferHubDefs::kHighBitsMask;
+ // Set the producer client buffer state to released, that of all other clients
+ // (both existing and non-existing clients) to posted.
+ uint32_t updated_buffer_state =
+ (~client_state_mask()) & BufferHubDefs::kHighBitsMask;
while (!buffer_state_->compare_exchange_weak(
current_buffer_state, updated_buffer_state, std::memory_order_acq_rel,
std::memory_order_acquire)) {
@@ -176,7 +173,9 @@
}
if (BufferHubDefs::AnyClientAcquired(current_buffer_state) ||
BufferHubDefs::AnyClientGained(current_buffer_state) ||
- (BufferHubDefs::AnyClientPosted(current_buffer_state) &&
+ (BufferHubDefs::AnyClientPosted(
+ current_buffer_state &
+ active_clients_bit_mask_->load(std::memory_order_acquire)) &&
!gain_posted_buffer)) {
ALOGE("%s: not released id=%d state=%" PRIx32 ".", __FUNCTION__, id(),
current_buffer_state);
@@ -198,7 +197,9 @@
if (BufferHubDefs::AnyClientAcquired(current_buffer_state) ||
BufferHubDefs::AnyClientGained(current_buffer_state) ||
- (BufferHubDefs::AnyClientPosted(current_buffer_state) &&
+ (BufferHubDefs::AnyClientPosted(
+ current_buffer_state &
+ active_clients_bit_mask_->load(std::memory_order_acquire)) &&
!gain_posted_buffer)) {
ALOGE(
"%s: Failed to gain the buffer. The buffer is no longer released. "
diff --git a/services/vr/bufferhubd/producer_channel.cpp b/services/vr/bufferhubd/producer_channel.cpp
index 2a6e9da..409bce9 100644
--- a/services/vr/bufferhubd/producer_channel.cpp
+++ b/services/vr/bufferhubd/producer_channel.cpp
@@ -369,7 +369,9 @@
(consumer_state_mask & BufferHubDefs::kHighBitsMask);
}
}
- if (update_buffer_state) {
+ if (update_buffer_state || BufferHubDefs::IsClientPosted(
+ buffer_state_->load(std::memory_order_acquire),
+ consumer_state_mask)) {
consumer->OnProducerPosted();
}
@@ -537,8 +539,13 @@
uint32_t current_buffer_state =
buffer_state_->load(std::memory_order_acquire);
+ uint32_t current_active_clients_bit_mask =
+ active_clients_bit_mask_->load(std::memory_order_acquire);
+ // Signal producer if all current active consumers have released the buffer.
if (BufferHubDefs::IsBufferReleased(current_buffer_state &
- ~orphaned_consumer_bit_mask_)) {
+ ~orphaned_consumer_bit_mask_ &
+ current_active_clients_bit_mask)) {
+ buffer_state_->store(0U);
SignalAvailable();
if (orphaned_consumer_bit_mask_) {
ALOGW(
@@ -564,8 +571,13 @@
uint32_t current_buffer_state =
buffer_state_->load(std::memory_order_acquire);
+ uint32_t current_active_clients_bit_mask =
+ active_clients_bit_mask_->load(std::memory_order_acquire);
+ // Signal producer if all current active consumers have released the buffer.
if (BufferHubDefs::IsBufferReleased(current_buffer_state &
- ~orphaned_consumer_bit_mask_)) {
+ ~orphaned_consumer_bit_mask_ &
+ current_active_clients_bit_mask)) {
+ buffer_state_->store(0U);
SignalAvailable();
}