Eliminate code duplication from hwcomposer
Move all common code to guest/hals/hwcomposer/common, which includes
the implementation of cpu-based compositions (vsoc_composer.* files
are renamed to cpu_composer.*).
Encapsulate the differences in classes implementing the contract
defined in the ScreenView abstract class (VsocketScreenView for crosvm
and VSoCScreenView for qemu).
Fix formatting of some files.
Bug: 135628605
Test: run locally with qemu & crosvm
Change-Id: Iae3c8a31155f935a4ee60ef1e16c934ad4878587
diff --git a/guest/hals/hwcomposer/common/Android.bp b/guest/hals/hwcomposer/common/Android.bp
index 5e16041..1b5125a 100644
--- a/guest/hals/hwcomposer/common/Android.bp
+++ b/guest/hals/hwcomposer/common/Android.bp
@@ -17,6 +17,28 @@
name: "hwcomposer_common",
defaults: ["cuttlefish_guest_only"],
vendor: true,
- srcs: ["hwcomposer.cpp"],
- shared_libs: ["libhardware", "liblog"],
+ srcs: [
+ "hwcomposer.cpp",
+ "screen_view.cpp",
+ "base_composer.cpp",
+ "geometry_utils.cpp",
+ "cpu_composer.cpp",
+ "stats_keeper.cpp",
+ ],
+ static_libs: [
+ "libyuv_static",
+ ],
+ shared_libs: [
+ "cuttlefish_auto_resources",
+ "liblog",
+ "libhardware",
+ "libbase",
+ "libcutils",
+ "libutils",
+ "libsync",
+ "libhardware",
+ "libjpeg",
+ "libcuttlefish_utils",
+ "libcuttlefish_fs",
+ ],
}
diff --git a/guest/hals/hwcomposer/common/base_composer.cpp b/guest/hals/hwcomposer/common/base_composer.cpp
new file mode 100644
index 0000000..61e6e99
--- /dev/null
+++ b/guest/hals/hwcomposer/common/base_composer.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include "guest/hals/hwcomposer/common/base_composer.h"
+
+#include <string.h>
+
+#include <cutils/properties.h>
+#include <hardware/gralloc.h>
+#include <log/log.h>
+
+#include "guest/hals/gralloc/legacy/gralloc_vsoc_priv.h"
+
+namespace cvd {
+
+BaseComposer::BaseComposer(int64_t vsync_base_timestamp,
+ std::unique_ptr<ScreenView> screen_view)
+ : screen_view_(std::move(screen_view)),
+ vsync_base_timestamp_(vsync_base_timestamp),
+ vsync_period_ns_(1e9 / screen_view_->refresh_rate()) {
+ hw_get_module(GRALLOC_HARDWARE_MODULE_ID,
+ reinterpret_cast<const hw_module_t**>(&gralloc_module_));
+}
+
+void BaseComposer::Dump(char* buff __unused, int buff_len __unused) {}
+
+int BaseComposer::PostFrameBufferTarget(buffer_handle_t buffer_handle) {
+ auto buffer_id = screen_view_->NextBuffer();
+ void* frame_buffer = screen_view_->GetBuffer(buffer_id);
+ const private_handle_t* p_handle =
+ reinterpret_cast<const private_handle_t*>(buffer_handle);
+ void* buffer;
+ int retval = gralloc_module_->lock(gralloc_module_, buffer_handle,
+ GRALLOC_USAGE_SW_READ_OFTEN, 0, 0,
+ p_handle->x_res, p_handle->y_res, &buffer);
+ if (retval != 0) {
+ ALOGE("Got error code %d from lock function", retval);
+ return -1;
+ }
+ memcpy(frame_buffer, buffer, screen_view_->buffer_size());
+ screen_view_->Broadcast(buffer_id);
+ return 0;
+} // namespace cvd
+
+int BaseComposer::PrepareLayers(size_t num_layers, cvd_hwc_layer* layers) {
+ // find unsupported overlays
+ for (size_t i = 0; i < num_layers; i++) {
+ if (IS_TARGET_FRAMEBUFFER(layers[i].compositionType)) {
+ continue;
+ }
+ layers[i].compositionType = HWC_FRAMEBUFFER;
+ }
+ return 0;
+}
+
+int BaseComposer::SetLayers(size_t num_layers, cvd_hwc_layer* layers) {
+ for (size_t idx = 0; idx < num_layers; idx++) {
+ if (IS_TARGET_FRAMEBUFFER(layers[idx].compositionType)) {
+ return PostFrameBufferTarget(layers[idx].handle);
+ }
+ }
+ return -1;
+}
+
+} // namespace cvd
diff --git a/guest/hals/hwcomposer/common/base_composer.h b/guest/hals/hwcomposer/common/base_composer.h
new file mode 100644
index 0000000..8e7dd36
--- /dev/null
+++ b/guest/hals/hwcomposer/common/base_composer.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#pragma once
+
+#include <memory>
+
+#include "guest/hals/hwcomposer/common/hwcomposer.h"
+#include "guest/hals/hwcomposer/common/screen_view.h"
+
+namespace cvd {
+
+class BaseComposer {
+ public:
+ BaseComposer(int64_t vsync_base_timestamp,
+ std::unique_ptr<ScreenView> screen_view);
+ ~BaseComposer() = default;
+
+ // Sets the composition type of each layer and returns the number of layers
+ // to be composited by the hwcomposer.
+ int PrepareLayers(size_t num_layers, cvd_hwc_layer* layers);
+ // Returns 0 if successful.
+ int SetLayers(size_t num_layers, cvd_hwc_layer* layers);
+ void Dump(char* buff, int buff_len);
+
+ int32_t x_res() { return screen_view_->x_res(); }
+ int32_t y_res() { return screen_view_->y_res(); }
+ int32_t dpi() { return screen_view_->dpi(); }
+ int32_t refresh_rate() { return screen_view_->refresh_rate(); }
+
+ protected:
+ std::unique_ptr<ScreenView> screen_view_;
+ const gralloc_module_t* gralloc_module_;
+ int64_t vsync_base_timestamp_;
+ int32_t vsync_period_ns_;
+
+ private:
+ // Returns buffer offset or negative on error.
+ int PostFrameBufferTarget(buffer_handle_t handle);
+};
+} // namespace cvd
diff --git a/guest/hals/hwcomposer/cutf_cvm/vsoc_composer.cpp b/guest/hals/hwcomposer/common/cpu_composer.cpp
similarity index 91%
rename from guest/hals/hwcomposer/cutf_cvm/vsoc_composer.cpp
rename to guest/hals/hwcomposer/common/cpu_composer.cpp
index 5b55e84..5e7a29d 100644
--- a/guest/hals/hwcomposer/cutf_cvm/vsoc_composer.cpp
+++ b/guest/hals/hwcomposer/common/cpu_composer.cpp
@@ -14,28 +14,27 @@
* limitations under the License.
*/
-#include "vsoc_composer.h"
+#include "guest/hals/hwcomposer/common/cpu_composer.h"
#include <algorithm>
#include <cstdlib>
#include <utility>
#include <vector>
-#include <log/log.h>
#include <hardware/hwcomposer.h>
#include <hardware/hwcomposer_defs.h>
#include <libyuv.h>
+#include <log/log.h>
#include <system/graphics.h>
-#include <common/libs/utils/size_utils.h>
-
-#include "geometry_utils.h"
+#include "common/libs/utils/size_utils.h"
+#include "guest/hals/hwcomposer/common/geometry_utils.h"
namespace cvd {
namespace {
-bool LayerNeedsScaling(const vsoc_hwc_layer& layer) {
+bool LayerNeedsScaling(const cvd_hwc_layer& layer) {
int from_w = layer.sourceCrop.right - layer.sourceCrop.left;
int from_h = layer.sourceCrop.bottom - layer.sourceCrop.top;
int to_w = layer.displayFrame.right - layer.displayFrame.left;
@@ -49,11 +48,11 @@
return needs_rot ? rot_scale : not_rot_scale;
}
-bool LayerNeedsBlending(const vsoc_hwc_layer& layer) {
+bool LayerNeedsBlending(const cvd_hwc_layer& layer) {
return layer.blending != HWC_BLENDING_NONE;
}
-bool LayerNeedsAttenuation(const vsoc_hwc_layer& layer) {
+bool LayerNeedsAttenuation(const cvd_hwc_layer& layer) {
return layer.blending == HWC_BLENDING_COVERAGE;
}
@@ -103,7 +102,7 @@
// Whether we support a given format
bool IsFormatSupported(uint32_t format) { return GetConverter(format) != NULL; }
-bool CanCompositeLayer(const vsoc_hwc_layer& layer) {
+bool CanCompositeLayer(const cvd_hwc_layer& layer) {
if (layer.handle == NULL) {
ALOGW("%s received a layer with a null handler", __FUNCTION__);
return false;
@@ -175,7 +174,7 @@
int stride_y = stride_in_pixels;
uint8_t* src_v = src_y + stride_y * src.height;
int stride_v = cvd::AlignToPowerOf2(stride_y / 2, 4);
- uint8_t* src_u = src_v + stride_v * src.height / 2;
+ uint8_t* src_u = src_v + stride_v * src.height / 2;
int stride_u = cvd::AlignToPowerOf2(stride_y / 2, 4);
// Adjust for crop
@@ -293,8 +292,7 @@
} // namespace
-void VSoCComposer::CompositeLayer(vsoc_hwc_layer* src_layer,
- int buffer_idx) {
+void CpuComposer::CompositeLayer(cvd_hwc_layer* src_layer, int buffer_idx) {
libyuv::RotationMode rotation =
GetRotationFromTransform(src_layer->transform);
@@ -313,8 +311,8 @@
needs_vflip || needs_attenuation || needs_blending);
uint8_t* src_buffer;
- uint8_t* dst_buffer = reinterpret_cast<uint8_t*>(
- frame_buffer_.GetBuffer(buffer_idx));
+ uint8_t* dst_buffer =
+ reinterpret_cast<uint8_t*>(screen_view_->GetBuffer(buffer_idx));
int retval = gralloc_module_->lock(
gralloc_module_, src_layer->handle, GRALLOC_USAGE_SW_READ_OFTEN, 0, 0,
src_priv_handle->x_res, src_priv_handle->y_res,
@@ -342,9 +340,9 @@
src_layer->sourceCrop.bottom - src_layer->sourceCrop.top;
src_layer_spec.format = src_priv_handle->format;
- BufferSpec dst_layer_spec(dst_buffer, frame_buffer_.buffer_size(),
- frame_buffer_.x_res(), frame_buffer_.y_res(),
- frame_buffer_.line_length());
+ BufferSpec dst_layer_spec(dst_buffer, screen_view_->buffer_size(),
+ screen_view_->x_res(), screen_view_->y_res(),
+ screen_view_->line_length());
dst_layer_spec.crop_x = src_layer->displayFrame.left;
dst_layer_spec.crop_y = src_layer->displayFrame.top;
dst_layer_spec.crop_width =
@@ -372,13 +370,11 @@
int x_res = src_layer->displayFrame.right - src_layer->displayFrame.left;
int y_res = src_layer->displayFrame.bottom - src_layer->displayFrame.top;
size_t output_frame_size =
- x_res *
- cvd::AlignToPowerOf2(y_res * frame_buffer_.bytes_per_pixel(), 4);
+ x_res * cvd::AlignToPowerOf2(y_res * screen_view_->bytes_per_pixel(), 4);
while (needed_tmp_buffers > 0) {
- BufferSpec tmp(RotateTmpBuffer(needed_tmp_buffers), output_frame_size,
- x_res, y_res,
- cvd::AlignToPowerOf2(
- x_res * frame_buffer_.bytes_per_pixel(), 4));
+ BufferSpec tmp(
+ RotateTmpBuffer(needed_tmp_buffers), output_frame_size, x_res, y_res,
+ cvd::AlignToPowerOf2(x_res * screen_view_->bytes_per_pixel(), 4));
dest_buffer_stack.push_back(tmp);
needed_tmp_buffers--;
}
@@ -399,8 +395,8 @@
// Make width and height match the crop sizes on the source
int src_width = src_layer_spec.crop_width;
int src_height = src_layer_spec.crop_height;
- int dst_stride = cvd::AlignToPowerOf2(
- src_width * frame_buffer_.bytes_per_pixel(), 4);
+ int dst_stride =
+ cvd::AlignToPowerOf2(src_width * screen_view_->bytes_per_pixel(), 4);
size_t needed_size = dst_stride * src_height;
dst_buffer_spec.width = src_width;
dst_buffer_spec.height = src_height;
@@ -440,7 +436,7 @@
// TODO (jemoreira): Aligment (To align here may cause the needed size to
// be bigger than the buffer, so care should be taken)
dst_buffer_spec.stride =
- dst_buffer_spec.width * frame_buffer_.bytes_per_pixel();
+ dst_buffer_spec.width * screen_view_->bytes_per_pixel();
}
retval = DoScaling(src_layer_spec, dst_buffer_spec, needs_vflip);
needs_vflip = false;
@@ -498,16 +494,14 @@
gralloc_module_->unlock(gralloc_module_, src_priv_handle);
}
-/* static */ const int VSoCComposer::kNumTmpBufferPieces = 2;
+/* static */ const int CpuComposer::kNumTmpBufferPieces = 2;
-VSoCComposer::VSoCComposer(int64_t vsync_base_timestamp)
- : BaseComposer(vsync_base_timestamp),
- tmp_buffer_(kNumTmpBufferPieces *
- frame_buffer_.buffer_size()) {}
+CpuComposer::CpuComposer(int64_t vsync_base_timestamp,
+ std::unique_ptr<ScreenView> screen_view)
+ : BaseComposer(vsync_base_timestamp, std::move(screen_view)),
+ tmp_buffer_(kNumTmpBufferPieces * screen_view_->buffer_size()) {}
-VSoCComposer::~VSoCComposer() {}
-
-int VSoCComposer::PrepareLayers(size_t num_layers, vsoc_hwc_layer* layers) {
+int CpuComposer::PrepareLayers(size_t num_layers, cvd_hwc_layer* layers) {
int composited_layers_count = 0;
// Loop over layers in inverse order of z-index
@@ -549,9 +543,9 @@
return composited_layers_count;
}
-int VSoCComposer::SetLayers(size_t num_layers, vsoc_hwc_layer* layers) {
+int CpuComposer::SetLayers(size_t num_layers, cvd_hwc_layer* layers) {
int targetFbs = 0;
- int buffer_idx = frame_buffer_.NextScreenBuffer();
+ int buffer_idx = screen_view_->NextBuffer();
// The framebuffer target layer should be composed if at least one layers was
// marked HWC_FRAMEBUFFER or if it's the only layer in the composition
@@ -591,16 +585,16 @@
if (targetFbs != 1) {
ALOGW("Saw %zu layers, posted=%d", num_layers, targetFbs);
}
- frame_buffer_.Broadcast(buffer_idx);
+ screen_view_->Broadcast(buffer_idx);
return 0;
}
-uint8_t* VSoCComposer::RotateTmpBuffer(unsigned int order) {
+uint8_t* CpuComposer::RotateTmpBuffer(unsigned int order) {
return &tmp_buffer_[(order % kNumTmpBufferPieces) * tmp_buffer_.size() /
kNumTmpBufferPieces];
}
-uint8_t* VSoCComposer::GetSpecialTmpBuffer(size_t needed_size) {
+uint8_t* CpuComposer::GetSpecialTmpBuffer(size_t needed_size) {
special_tmp_buffer_.resize(needed_size);
return &special_tmp_buffer_[0];
}
diff --git a/guest/hals/hwcomposer/vsoc/vsoc_composer.h b/guest/hals/hwcomposer/common/cpu_composer.h
similarity index 69%
rename from guest/hals/hwcomposer/vsoc/vsoc_composer.h
rename to guest/hals/hwcomposer/common/cpu_composer.h
index 0e8e2c2..3e745df 100644
--- a/guest/hals/hwcomposer/vsoc/vsoc_composer.h
+++ b/guest/hals/hwcomposer/common/cpu_composer.h
@@ -1,4 +1,3 @@
-#pragma once
/*
* Copyright (C) 2016 The Android Open Source Project
*
@@ -15,32 +14,35 @@
* limitations under the License.
*/
+#pragma once
+
#include <vector>
#include <hardware/gralloc.h>
#include "guest/hals/gralloc/legacy/gralloc_vsoc_priv.h"
-#include "base_composer.h"
-#include "hwcomposer.h"
+#include "guest/hals/hwcomposer/common/base_composer.h"
+#include "guest/hals/hwcomposer/common/hwcomposer.h"
namespace cvd {
-class VSoCComposer : public BaseComposer {
+class CpuComposer : public BaseComposer {
public:
- VSoCComposer(int64_t vsync_base_timestamp, int32_t vsync_period_ns);
- ~VSoCComposer();
+ CpuComposer(int64_t vsync_base_timestamp,
+ std::unique_ptr<ScreenView> screen_view);
+ ~CpuComposer() = default;
// override
- int PrepareLayers(size_t num_layers, vsoc_hwc_layer* layers);
+ int PrepareLayers(size_t num_layers, cvd_hwc_layer* layers);
// override
- int SetLayers(size_t num_layers, vsoc_hwc_layer* layers);
+ int SetLayers(size_t num_layers, cvd_hwc_layer* layers);
protected:
static const int kNumTmpBufferPieces;
uint8_t* RotateTmpBuffer(unsigned int order);
uint8_t* GetSpecialTmpBuffer(size_t needed_size);
- void CompositeLayer(vsoc_hwc_layer* src_layer, int32_t fb_offset);
+ void CompositeLayer(cvd_hwc_layer* src_layer, int32_t fb_offset);
std::vector<uint8_t> tmp_buffer_;
std::vector<uint8_t> special_tmp_buffer_;
};
diff --git a/guest/hals/hwcomposer/cutf_cvm/geometry_utils.cpp b/guest/hals/hwcomposer/common/geometry_utils.cpp
similarity index 89%
rename from guest/hals/hwcomposer/cutf_cvm/geometry_utils.cpp
rename to guest/hals/hwcomposer/common/geometry_utils.cpp
index 75b7a61..a348026 100644
--- a/guest/hals/hwcomposer/cutf_cvm/geometry_utils.cpp
+++ b/guest/hals/hwcomposer/common/geometry_utils.cpp
@@ -14,13 +14,14 @@
* limitations under the License.
*/
-#include "geometry_utils.h"
+#include "guest/hals/hwcomposer/common/geometry_utils.h"
+
#include <algorithm>
#include <utility>
namespace cvd {
-bool LayersOverlap(const vsoc_hwc_layer& layer1, const vsoc_hwc_layer& layer2) {
+bool LayersOverlap(const cvd_hwc_layer& layer1, const cvd_hwc_layer& layer2) {
int left1 = layer1.displayFrame.left;
int right1 = layer1.displayFrame.right;
int top1 = layer1.displayFrame.top;
diff --git a/guest/hals/hwcomposer/cutf_cvm/geometry_utils.h b/guest/hals/hwcomposer/common/geometry_utils.h
similarity index 83%
rename from guest/hals/hwcomposer/cutf_cvm/geometry_utils.h
rename to guest/hals/hwcomposer/common/geometry_utils.h
index 937283f..aadaec3 100644
--- a/guest/hals/hwcomposer/cutf_cvm/geometry_utils.h
+++ b/guest/hals/hwcomposer/common/geometry_utils.h
@@ -15,10 +15,10 @@
* limitations under the License.
*/
-#include "hwcomposer.h"
+#include "guest/hals/hwcomposer/common/hwcomposer.h"
namespace cvd {
-bool LayersOverlap(const vsoc_hwc_layer& layer1, const vsoc_hwc_layer& layer2);
+bool LayersOverlap(const cvd_hwc_layer& layer1, const cvd_hwc_layer& layer2);
} // namespace cvd
diff --git a/guest/hals/hwcomposer/common/hwcomposer.cpp b/guest/hals/hwcomposer/common/hwcomposer.cpp
index 56b2315..84de82d 100644
--- a/guest/hals/hwcomposer/common/hwcomposer.cpp
+++ b/guest/hals/hwcomposer/common/hwcomposer.cpp
@@ -14,18 +14,67 @@
* limitations under the License.
*/
+// Versions of hwcomposer we implement:
+// JB: 0.3
+// JB-MR1 to N : 1.1
+// N-MR1 to ... : We report 1.1 but SurfaceFlinger has the option to use an
+// adapter to treat our 1.1 hwcomposer as a 2.0. If SF stops using that adapter
+// to support 1.1 implementations it can be copied into cuttlefish from
+// frameworks/native/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.*
+
#define LOG_TAG "hwc.cf_x86"
#define HWC_REMOVE_DEPRECATED_VERSIONS 1
-#include "hwcomposer.h"
+#include "guest/hals/hwcomposer/common/hwcomposer.h"
#include <errno.h>
+#include <fcntl.h>
+#include <math.h>
+#include <poll.h>
+#include <pthread.h>
#include <stdio.h>
+#include <stdlib.h>
+#include <sync/sync.h>
#include <sys/resource.h>
#include <sys/time.h>
+
#include <string>
+#include <cutils/compiler.h>
+#include <cutils/properties.h>
+#include <hardware/gralloc.h>
+#include <hardware/hardware.h>
+#include <hardware/hwcomposer.h>
+#include <hardware/hwcomposer_defs.h>
#include <log/log.h>
+#include <utils/String8.h>
+#include <utils/Vector.h>
+
+#include "guest/hals/gralloc/legacy/gralloc_vsoc_priv.h"
+#include "guest/libs/platform_support/api_level_fixes.h"
+
+#include "guest/hals/hwcomposer/common/base_composer.h"
+#include "guest/hals/hwcomposer/common/cpu_composer.h"
+#include "guest/hals/hwcomposer/common/geometry_utils.h"
+#include "guest/hals/hwcomposer/common/hwcomposer.h"
+
+#ifdef USE_OLD_HWCOMPOSER
+typedef cvd::BaseComposer InnerComposerType;
+#else
+typedef cvd::CpuComposer InnerComposerType;
+#endif
+
+#ifdef GATHER_STATS
+typedef cvd::StatsKeepingComposer<InnerComposerType> ComposerType;
+#else
+typedef InnerComposerType ComposerType;
+#endif
+
+struct cvd_hwc_composer_device_1_t {
+ cvd_hwc_device base;
+ cvd::hwc_composer_device_data_t vsync_data;
+ ComposerType* composer;
+};
namespace cvd {
@@ -45,7 +94,7 @@
struct timespec rt;
if (clock_gettime(CLOCK_MONOTONIC, &rt) == -1) {
LOG_ALWAYS_FATAL("%s:%d error in vsync thread clock_gettime: %s",
- __FILE__, __LINE__, strerror(errno));
+ __FILE__, __LINE__, strerror(errno));
}
int64_t timestamp = int64_t(rt.tv_sec) * 1e9 + rt.tv_nsec;
@@ -90,3 +139,401 @@
}
} // namespace cvd
+
+namespace {
+
+std::string CompositionString(int type) {
+ switch (type) {
+ case HWC_FRAMEBUFFER:
+ return "Framebuffer";
+ case HWC_OVERLAY:
+ return "Overlay";
+ case HWC_BACKGROUND:
+ return "Background";
+ case HWC_FRAMEBUFFER_TARGET:
+ return "FramebufferTarget";
+#if VSOC_PLATFORM_SDK_AFTER(K)
+ case HWC_SIDEBAND:
+ return "Sideband";
+ case HWC_CURSOR_OVERLAY:
+ return "CursorOverlay";
+#endif
+ default:
+ return std::string("Unknown (") + std::to_string(type) + ")";
+ }
+}
+
+void LogLayers(int num_layers, cvd_hwc_layer* layers, int invalid) {
+ ALOGE("Layers:");
+ for (int idx = 0; idx < num_layers; ++idx) {
+ std::string log_line;
+ if (idx == invalid) {
+ log_line = "Invalid layer: ";
+ }
+ log_line +=
+ "Composition Type: " + CompositionString(layers[idx].compositionType);
+ ALOGE("%s", log_line.c_str());
+ }
+}
+
+// Ensures that the layer does not include any inconsistencies
+bool IsValidLayer(const cvd_hwc_layer& layer) {
+ if (layer.flags & HWC_SKIP_LAYER) {
+ // A layer we are asked to skip validate should not be marked as skip
+ ALOGE("%s: Layer is marked as skip", __FUNCTION__);
+ return false;
+ }
+ // Check displayFrame
+ if (layer.displayFrame.left > layer.displayFrame.right ||
+ layer.displayFrame.top > layer.displayFrame.bottom) {
+ ALOGE(
+ "%s: Malformed rectangle (displayFrame): [left = %d, right = %d, top = "
+ "%d, bottom = %d]",
+ __FUNCTION__, layer.displayFrame.left, layer.displayFrame.right,
+ layer.displayFrame.top, layer.displayFrame.bottom);
+ return false;
+ }
+ // Validate the handle
+ if (private_handle_t::validate(layer.handle) != 0) {
+ ALOGE("%s: Layer contains an invalid gralloc handle.", __FUNCTION__);
+ return false;
+ }
+ const private_handle_t* p_handle =
+ reinterpret_cast<const private_handle_t*>(layer.handle);
+ // Check sourceCrop
+ if (layer.sourceCrop.left > layer.sourceCrop.right ||
+ layer.sourceCrop.top > layer.sourceCrop.bottom) {
+ ALOGE(
+ "%s: Malformed rectangle (sourceCrop): [left = %d, right = %d, top = "
+ "%d, bottom = %d]",
+ __FUNCTION__, layer.sourceCrop.left, layer.sourceCrop.right,
+ layer.sourceCrop.top, layer.sourceCrop.bottom);
+ return false;
+ }
+ if (layer.sourceCrop.left < 0 || layer.sourceCrop.top < 0 ||
+ layer.sourceCrop.right > p_handle->x_res ||
+ layer.sourceCrop.bottom > p_handle->y_res) {
+ ALOGE(
+ "%s: Invalid sourceCrop for buffer handle: sourceCrop = [left = %d, "
+ "right = %d, top = %d, bottom = %d], handle = [width = %d, height = "
+ "%d]",
+ __FUNCTION__, layer.sourceCrop.left, layer.sourceCrop.right,
+ layer.sourceCrop.top, layer.sourceCrop.bottom, p_handle->x_res,
+ p_handle->y_res);
+ return false;
+ }
+ return true;
+}
+
+bool IsValidComposition(int num_layers, cvd_hwc_layer* layers, bool on_set) {
+ if (num_layers == 0) {
+ ALOGE("Composition requested with 0 layers");
+ return false;
+ }
+ // Sometimes the hwcomposer receives a prepare and set calls with no other
+ // layer than the FRAMEBUFFER_TARGET with a null handler. We treat this case
+ // independently as a valid composition, but issue a warning about it.
+ if (num_layers == 1 && layers[0].compositionType == HWC_FRAMEBUFFER_TARGET &&
+ layers[0].handle == NULL) {
+ ALOGW("Received request for empty composition, treating as valid noop");
+ return true;
+ }
+ // The FRAMEBUFFER_TARGET layer needs to be sane only if
+ // there is at least one layer marked HWC_FRAMEBUFFER or if there is no layer
+ // marked HWC_OVERLAY (i.e some layers where composed with OpenGL, no layer
+ // marked overlay or framebuffer means that surfaceflinger decided to go for
+ // OpenGL without asking the hwcomposer first)
+ bool check_fb_target = true;
+ for (int idx = 0; idx < num_layers; ++idx) {
+ if (layers[idx].compositionType == HWC_FRAMEBUFFER) {
+ // There is at least one, so it needs to be checked.
+ // It may have been set to false before, so ensure it's set to true.
+ check_fb_target = true;
+ break;
+ }
+ if (layers[idx].compositionType == HWC_OVERLAY) {
+ // At least one overlay, we may not need to.
+ check_fb_target = false;
+ }
+ }
+
+ for (int idx = 0; idx < num_layers; ++idx) {
+ switch (layers[idx].compositionType) {
+ case HWC_FRAMEBUFFER_TARGET:
+ // In the call to prepare() the framebuffer target does not have a valid
+ // buffer_handle, so we don't validate it yet.
+ if (on_set && check_fb_target && !IsValidLayer(layers[idx])) {
+ ALOGE("%s: Invalid layer found", __FUNCTION__);
+ LogLayers(num_layers, layers, idx);
+ return false;
+ }
+ break;
+ case HWC_OVERLAY:
+ if (!(layers[idx].flags & HWC_SKIP_LAYER) &&
+ !IsValidLayer(layers[idx])) {
+ ALOGE("%s: Invalid layer found", __FUNCTION__);
+ LogLayers(num_layers, layers, idx);
+ return false;
+ }
+ break;
+ }
+ }
+ return true;
+}
+
+} // namespace
+
+#if VSOC_PLATFORM_SDK_BEFORE(J_MR1)
+static int cvd_hwc_prepare(cvd_hwc_device* dev, hwc_layer_list_t* list) {
+#else
+static int cvd_hwc_prepare(cvd_hwc_device* dev, size_t numDisplays,
+ hwc_display_contents_1_t** displays) {
+ if (!numDisplays || !displays) return 0;
+
+ hwc_display_contents_1_t* list = displays[HWC_DISPLAY_PRIMARY];
+
+ if (!list) return 0;
+#endif
+ if (!IsValidComposition(list->numHwLayers, &list->hwLayers[0], false)) {
+ LOG_ALWAYS_FATAL("%s: Invalid composition requested", __FUNCTION__);
+ return -1;
+ }
+ reinterpret_cast<cvd_hwc_composer_device_1_t*>(dev)->composer->PrepareLayers(
+ list->numHwLayers, &list->hwLayers[0]);
+ return 0;
+}
+
+#if VSOC_PLATFORM_SDK_BEFORE(J_MR1)
+int cvd_hwc_set(struct hwc_composer_device* dev, hwc_display_t dpy,
+ hwc_surface_t sur, hwc_layer_list_t* list) {
+ if (list->numHwLayers == 1 &&
+ layers[0].compositionType == HWC_FRAMEBUFFER_TARGET) {
+ ALOGW("Received request for empty composition, treating as valid noop");
+ return 0;
+ }
+ if (!IsValidComposition(list->numHwLayers, &list->hwLayers[0], true)) {
+ LOG_ALWAYS_FATAL("%s: Invalid composition requested", __FUNCTION__);
+ return -1;
+ }
+ return reinterpret_cast<cvd_hwc_composer_device_1_t*>(dev)
+ ->composer->SetLayers(list->numHwLayers, &list->hwLayers[0]);
+}
+#else
+static int cvd_hwc_set(cvd_hwc_device* dev, size_t numDisplays,
+ hwc_display_contents_1_t** displays) {
+ if (!numDisplays || !displays) return 0;
+
+ hwc_display_contents_1_t* contents = displays[HWC_DISPLAY_PRIMARY];
+ if (!contents) return 0;
+
+ cvd_hwc_layer* layers = &contents->hwLayers[0];
+ if (contents->numHwLayers == 1 &&
+ layers[0].compositionType == HWC_FRAMEBUFFER_TARGET) {
+ ALOGW("Received request for empty composition, treating as valid noop");
+ return 0;
+ }
+ if (!IsValidComposition(contents->numHwLayers, layers, true)) {
+ LOG_ALWAYS_FATAL("%s: Invalid composition requested", __FUNCTION__);
+ return -1;
+ }
+ int retval =
+ reinterpret_cast<cvd_hwc_composer_device_1_t*>(dev)->composer->SetLayers(
+ contents->numHwLayers, layers);
+
+ int closedFds = 0;
+ for (size_t index = 0; index < contents->numHwLayers; ++index) {
+ if (layers[index].acquireFenceFd != -1) {
+ close(layers[index].acquireFenceFd);
+ layers[index].acquireFenceFd = -1;
+ ++closedFds;
+ }
+ }
+ if (closedFds) {
+ ALOGI("Saw %zu layers, closed=%d", contents->numHwLayers, closedFds);
+ }
+
+ // TODO(ghartman): This should be set before returning. On the next set it
+ // should be signalled when we load the new frame.
+ contents->retireFenceFd = -1;
+ return retval;
+}
+#endif
+
+static void cvd_hwc_register_procs(cvd_hwc_device* dev,
+ const hwc_procs_t* procs) {
+ struct cvd_hwc_composer_device_1_t* pdev =
+ (struct cvd_hwc_composer_device_1_t*)dev;
+ pdev->vsync_data.procs = procs;
+}
+
+static int cvd_hwc_query(cvd_hwc_device* dev, int what, int* value) {
+ struct cvd_hwc_composer_device_1_t* pdev =
+ (struct cvd_hwc_composer_device_1_t*)dev;
+
+ switch (what) {
+ case HWC_BACKGROUND_LAYER_SUPPORTED:
+ // we support the background layer
+ value[0] = 0;
+ break;
+ case HWC_VSYNC_PERIOD:
+ value[0] = pdev->vsync_data.vsync_period_ns;
+ break;
+ default:
+ // unsupported query
+ ALOGE("%s badness unsupported query what=%d", __FUNCTION__, what);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int cvd_hwc_event_control(
+#if VSOC_PLATFORM_SDK_BEFORE(J_MR1)
+ cvd_hwc_device* /*dev*/, int event, int /*enabled*/) {
+#else
+ cvd_hwc_device* /*dev*/, int /*dpy*/, int event, int /*enabled*/) {
+#endif
+
+ if (event == HWC_EVENT_VSYNC) {
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static int cvd_hwc_blank(cvd_hwc_device* /*dev*/, int disp, int /*blank*/) {
+ if (!IS_PRIMARY_DISPLAY(disp)) return -EINVAL;
+ return 0;
+}
+
+static void cvd_hwc_dump(cvd_hwc_device* dev, char* buff, int buff_len) {
+ reinterpret_cast<cvd_hwc_composer_device_1_t*>(dev)->composer->Dump(buff,
+ buff_len);
+}
+
+static int cvd_hwc_get_display_configs(cvd_hwc_device* /*dev*/, int disp,
+ uint32_t* configs, size_t* numConfigs) {
+ if (*numConfigs == 0) return 0;
+
+ if (IS_PRIMARY_DISPLAY(disp)) {
+ configs[0] = 0;
+ *numConfigs = 1;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+#if VSOC_PLATFORM_SDK_AFTER(J)
+static int32_t cvd_hwc_attribute(struct cvd_hwc_composer_device_1_t* pdev,
+ const uint32_t attribute) {
+ switch (attribute) {
+ case HWC_DISPLAY_VSYNC_PERIOD:
+ return pdev->vsync_data.vsync_period_ns;
+ case HWC_DISPLAY_WIDTH:
+ return pdev->composer->x_res();
+ case HWC_DISPLAY_HEIGHT:
+ return pdev->composer->y_res();
+ case HWC_DISPLAY_DPI_X:
+ ALOGI("Reporting DPI_X of %d", pdev->composer->dpi());
+ // The number of pixels per thousand inches
+ return pdev->composer->dpi() * 1000;
+ case HWC_DISPLAY_DPI_Y:
+ ALOGI("Reporting DPI_Y of %d", pdev->composer->dpi());
+ // The number of pixels per thousand inches
+ return pdev->composer->dpi() * 1000;
+ default:
+ ALOGE("unknown display attribute %u", attribute);
+ return -EINVAL;
+ }
+}
+
+static int cvd_hwc_get_display_attributes(cvd_hwc_device* dev, int disp,
+ uint32_t config __unused,
+ const uint32_t* attributes,
+ int32_t* values) {
+ struct cvd_hwc_composer_device_1_t* pdev =
+ (struct cvd_hwc_composer_device_1_t*)dev;
+
+ if (!IS_PRIMARY_DISPLAY(disp)) {
+ ALOGE("unknown display type %u", disp);
+ return -EINVAL;
+ }
+
+ for (int i = 0; attributes[i] != HWC_DISPLAY_NO_ATTRIBUTE; i++) {
+ values[i] = cvd_hwc_attribute(pdev, attributes[i]);
+ }
+
+ return 0;
+}
+#endif
+
+static int cvd_hwc_close(hw_device_t* device) {
+ struct cvd_hwc_composer_device_1_t* dev =
+ (struct cvd_hwc_composer_device_1_t*)device;
+ ALOGE("cvd_hwc_close");
+ pthread_kill(dev->vsync_data.vsync_thread, SIGTERM);
+ pthread_join(dev->vsync_data.vsync_thread, NULL);
+ delete dev->composer;
+ delete dev;
+ return 0;
+}
+
+namespace cvd {
+
+int cvd_hwc_open(std::unique_ptr<ScreenView> screen_view,
+ const struct hw_module_t* module, const char* name,
+ struct hw_device_t** device) {
+ ALOGI("%s", __FUNCTION__);
+ if (strcmp(name, HWC_HARDWARE_COMPOSER)) {
+ ALOGE("%s called with bad name %s", __FUNCTION__, name);
+ return -EINVAL;
+ }
+
+ cvd_hwc_composer_device_1_t* dev = new cvd_hwc_composer_device_1_t();
+ if (!dev) {
+ ALOGE("%s failed to allocate dev", __FUNCTION__);
+ return -ENOMEM;
+ }
+
+ struct timespec rt;
+ if (clock_gettime(CLOCK_MONOTONIC, &rt) == -1) {
+ ALOGE("%s:%d error in vsync thread clock_gettime: %s", __FILE__, __LINE__,
+ strerror(errno));
+ }
+ dev->vsync_data.vsync_base_timestamp = int64_t(rt.tv_sec) * 1e9 + rt.tv_nsec;
+ dev->vsync_data.vsync_period_ns = 1e9 / screen_view->refresh_rate();
+
+ dev->base.common.tag = HARDWARE_DEVICE_TAG;
+ dev->base.common.version = VSOC_HWC_DEVICE_API_VERSION;
+ dev->base.common.module = const_cast<hw_module_t*>(module);
+ dev->base.common.close = cvd_hwc_close;
+
+ dev->base.prepare = cvd_hwc_prepare;
+ dev->base.set = cvd_hwc_set;
+ dev->base.query = cvd_hwc_query;
+ dev->base.registerProcs = cvd_hwc_register_procs;
+ dev->base.dump = cvd_hwc_dump;
+#if VSOC_PLATFORM_SDK_BEFORE(J_MR1)
+ static hwc_methods_t hwc_methods = {cvd_hwc_event_control};
+ dev->base.methods = &hwc_methods;
+#else
+ dev->base.blank = cvd_hwc_blank;
+ dev->base.eventControl = cvd_hwc_event_control;
+ dev->base.getDisplayConfigs = cvd_hwc_get_display_configs;
+ dev->base.getDisplayAttributes = cvd_hwc_get_display_attributes;
+#endif
+ dev->composer = new ComposerType(dev->vsync_data.vsync_base_timestamp,
+ std::move(screen_view));
+ int ret = pthread_create(&dev->vsync_data.vsync_thread, NULL,
+ cvd::hwc_vsync_thread, &dev->vsync_data);
+ if (ret) {
+ ALOGE("failed to start vsync thread: %s", strerror(ret));
+ ret = -ret;
+ delete dev;
+ } else {
+ *device = &dev->base.common;
+ }
+
+ return ret;
+}
+
+} // namespace cvd
diff --git a/guest/hals/hwcomposer/common/hwcomposer.h b/guest/hals/hwcomposer/common/hwcomposer.h
index 8c57e71..e326376 100644
--- a/guest/hals/hwcomposer/common/hwcomposer.h
+++ b/guest/hals/hwcomposer/common/hwcomposer.h
@@ -15,15 +15,40 @@
* limitations under the License.
*/
+#include <memory>
+
#include <hardware/hwcomposer.h>
+#include <hardware/hwcomposer_defs.h>
+
+#include "guest/libs/platform_support/api_level_fixes.h"
+
+#include "guest/hals/hwcomposer/common/screen_view.h"
+
+#if VSOC_PLATFORM_SDK_BEFORE(J_MR1)
+typedef hwc_composer_device_t cvd_hwc_device;
+typedef hwc_layer_t cvd_hwc_layer;
+#define IS_TARGET_FRAMEBUFFER(x) false
+#define IS_PRIMARY_DISPLAY(x) true
+#define VSOC_HWC_DEVICE_API_VERSION HWC_DEVICE_API_VERSION_0_3
+#else
+typedef hwc_composer_device_1_t cvd_hwc_device;
+typedef hwc_layer_1_t cvd_hwc_layer;
+#define IS_TARGET_FRAMEBUFFER(x) ((x) == HWC_FRAMEBUFFER_TARGET)
+#define IS_PRIMARY_DISPLAY(x) ((x) == HWC_DISPLAY_PRIMARY)
+#define VSOC_HWC_DEVICE_API_VERSION HWC_DEVICE_API_VERSION_1_1
+#endif
namespace cvd {
- struct hwc_composer_device_data_t {
- const hwc_procs_t* procs;
- pthread_t vsync_thread;
- int64_t vsync_base_timestamp;
- int32_t vsync_period_ns;
- };
+struct hwc_composer_device_data_t {
+ const hwc_procs_t* procs;
+ pthread_t vsync_thread;
+ int64_t vsync_base_timestamp;
+ int32_t vsync_period_ns;
+};
- void* hwc_vsync_thread(void* data);
+void* hwc_vsync_thread(void* data);
+
+int cvd_hwc_open(std::unique_ptr<ScreenView> screen_view,
+ const struct hw_module_t* module, const char* name,
+ struct hw_device_t** device);
} // namespace cvd
diff --git a/guest/hals/hwcomposer/common/screen_view.cpp b/guest/hals/hwcomposer/common/screen_view.cpp
new file mode 100644
index 0000000..48f9fa6
--- /dev/null
+++ b/guest/hals/hwcomposer/common/screen_view.cpp
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+#include "guest/hals/hwcomposer/common/screen_view.h"
+
+#include "common/libs/utils/size_utils.h"
+
+namespace cvd {
+
+int ScreenView::NextBuffer() {
+ int num_buffers = this->num_buffers();
+ last_buffer_ = num_buffers > 0 ? (last_buffer_ + 1) % num_buffers : -1;
+ return last_buffer_;
+}
+
+size_t ScreenView::buffer_size() const {
+ return line_length() * y_res() + 4 /* swiftshader padding */;
+}
+
+size_t ScreenView::line_length() const {
+ return cvd::AlignToPowerOf2(x_res() * bytes_per_pixel(), 4);
+}
+
+int ScreenView::bytes_per_pixel() const { return 4; }
+} // namespace cvd
diff --git a/guest/hals/hwcomposer/common/screen_view.h b/guest/hals/hwcomposer/common/screen_view.h
new file mode 100644
index 0000000..b985f8f
--- /dev/null
+++ b/guest/hals/hwcomposer/common/screen_view.h
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <sys/time.h>
+
+namespace cvd {
+
+struct CompositionStats {
+ uint32_t num_prepare_calls;
+ uint16_t num_layers;
+ uint16_t num_hwcomposited_layers;
+ timespec last_vsync;
+ timespec prepare_start;
+ timespec prepare_end;
+ timespec set_start;
+ timespec set_end;
+};
+
+class ScreenView {
+ public:
+ ScreenView() = default;
+ ScreenView(const ScreenView&) = delete;
+ virtual ~ScreenView() = default;
+
+ ScreenView& operator=(const ScreenView&) = delete;
+
+ virtual void Broadcast(int buffer_id,
+ const CompositionStats* stats = nullptr) = 0;
+ virtual int NextBuffer();
+ virtual void* GetBuffer(int buffer_id) = 0;
+
+ virtual int32_t x_res() const = 0;
+ virtual int32_t y_res() const = 0;
+ virtual int32_t dpi() const = 0;
+ virtual int32_t refresh_rate() const = 0;
+
+ size_t buffer_size() const;
+ size_t line_length() const;
+ int bytes_per_pixel() const;
+
+ virtual int num_buffers() const = 0;
+
+ private:
+ int last_buffer_ = 0;
+};
+} // namespace cvd
\ No newline at end of file
diff --git a/guest/hals/hwcomposer/vsoc/stats_keeper.cpp b/guest/hals/hwcomposer/common/stats_keeper.cpp
similarity index 96%
rename from guest/hals/hwcomposer/vsoc/stats_keeper.cpp
rename to guest/hals/hwcomposer/common/stats_keeper.cpp
index 5d87cd4..efff1d8 100644
--- a/guest/hals/hwcomposer/vsoc/stats_keeper.cpp
+++ b/guest/hals/hwcomposer/common/stats_keeper.cpp
@@ -14,15 +14,20 @@
* limitations under the License.
*/
-#include <log/log.h>
+#include "guest/hals/hwcomposer/common/stats_keeper.h"
+
+#include <inttypes.h>
+#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
+
#include <algorithm>
#include <utility>
#include <vector>
-#include "geometry_utils.h"
-#include "stats_keeper.h"
+#include <log/log.h>
+
+#include "guest/hals/hwcomposer/common/geometry_utils.h"
using cvd::LockGuard;
using cvd::Mutex;
@@ -31,8 +36,6 @@
using cvd::time::Nanoseconds;
using cvd::time::Seconds;
using cvd::time::TimeDifference;
-using vsoc::layout::screen::TimeSpec;
-using vsoc::layout::screen::CompositionStats;
namespace cvd {
@@ -53,9 +56,9 @@
return *mset.rbegin();
}
-void TimeDifferenceToTimeSpec(const TimeDifference& td, TimeSpec* ts) {
- ts->ts_sec = td.seconds();
- ts->ts_nsec = td.subseconds_in_ns();
+void TimeDifferenceToTimeSpec(const TimeDifference& td, timespec* ts) {
+ ts->tv_sec = td.seconds();
+ ts->tv_nsec = td.subseconds_in_ns();
}
} // namespace
diff --git a/guest/hals/hwcomposer/vsoc/stats_keeper.h b/guest/hals/hwcomposer/common/stats_keeper.h
similarity index 75%
rename from guest/hals/hwcomposer/vsoc/stats_keeper.h
rename to guest/hals/hwcomposer/common/stats_keeper.h
index e1dd330..8eb0e49 100644
--- a/guest/hals/hwcomposer/vsoc/stats_keeper.h
+++ b/guest/hals/hwcomposer/common/stats_keeper.h
@@ -22,9 +22,9 @@
#include "common/libs/threads/cuttlefish_thread.h"
#include "common/libs/time/monotonic_time.h"
-#include "common/vsoc/lib/screen_region_view.h"
-#include "hwcomposer.h"
+#include "guest/hals/hwcomposer/common/base_composer.h"
+#include "guest/hals/hwcomposer/common/hwcomposer.h"
namespace cvd {
@@ -94,7 +94,7 @@
void RecordSetStart();
void RecordSetEnd() EXCLUDES(mutex_);
- void GetLastCompositionStats(vsoc::layout::screen::CompositionStats* stats_p);
+ void GetLastCompositionStats(CompositionStats* stats_p);
// Calls to this function are synchronized with calls to 'RecordSetEnd' with a
// mutex. The other Record* functions do not need such synchronization because
@@ -146,38 +146,62 @@
mutable cvd::Mutex mutex_;
};
+class WrappedScreenView : public ScreenView {
+ public:
+ WrappedScreenView(std::unique_ptr<ScreenView> screen_view,
+ std::function<void(CompositionStats*)> stats_getter)
+ : screen_view_(std::move(screen_view)), stats_getter_(stats_getter) {}
+ virtual ~WrappedScreenView() = default;
+
+ void Broadcast(int buffer_id, const CompositionStats*) override {
+ // The composer object in stats_keeper produces null stats, use the ones
+ // provided by the stats_keeper instead.
+ CompositionStats stats;
+ stats_getter_(&stats);
+ return screen_view_->Broadcast(buffer_id, &stats);
+ }
+
+ void* GetBuffer(int buffer_id) override {
+ return screen_view_->GetBuffer(buffer_id);
+ }
+
+ int32_t x_res() const override { return screen_view_->x_res(); }
+
+ int32_t y_res() const override { return screen_view_->y_res(); }
+
+ int32_t dpi() const override { return screen_view_->dpi(); }
+
+ int32_t refresh_rate() const override { return screen_view_->refresh_rate(); }
+
+ int num_buffers() const override { return screen_view_->num_buffers(); }
+
+ private:
+ std::unique_ptr<ScreenView> screen_view_;
+ std::function<void(CompositionStats*)> stats_getter_;
+};
+
template <class Composer>
-class StatsKeepingComposer {
+class StatsKeepingComposer : public BaseComposer {
public:
// Keep stats from the last 10 seconds.
- StatsKeepingComposer(int64_t vsync_base_timestamp, int32_t vsync_period_ns)
- : stats_keeper_(cvd::time::TimeDifference(cvd::time::Seconds(10), 1),
- vsync_base_timestamp, vsync_period_ns),
- composer_(vsync_base_timestamp, vsync_period_ns) {
- // Don't let the composer broadcast by itself, allow it to return to collect
- // the timings and broadcast then.
- composer_.ReplaceFbBroadcaster([this](int buffer_index){
- BroadcastWithStats(buffer_index);
- });
- }
+ StatsKeepingComposer(int64_t vsync_base_timestamp,
+ std::unique_ptr<ScreenView> screen_view)
+ : composer_(vsync_base_timestamp,
+ std::unique_ptr<ScreenView>(new WrappedScreenView(
+ std::move(screen_view),
+ [this](CompositionStats* stats) { FinalizeStatsAndGet(stats); }))),
+ stats_keeper_(cvd::time::TimeDifference(cvd::time::Seconds(10), 1),
+ vsync_base_timestamp, 1e9 / composer_.refresh_rate()) {}
~StatsKeepingComposer() = default;
- int PrepareLayers(size_t num_layers, vsoc_hwc_layer* layers) {
+ int PrepareLayers(size_t num_layers, cvd_hwc_layer* layers) {
stats_keeper_.RecordPrepareStart(num_layers);
int num_hwc_layers = composer_.PrepareLayers(num_layers, layers);
stats_keeper_.RecordPrepareEnd(num_hwc_layers);
return num_hwc_layers;
}
- void BroadcastWithStats(int buffer_idx) {
- stats_keeper_.RecordSetEnd();
- vsoc::layout::screen::CompositionStats stats;
- stats_keeper_.GetLastCompositionStats(&stats);
- vsoc::screen::ScreenRegionView::GetInstance()
- ->BroadcastNewFrame(static_cast<uint32_t>(buffer_idx), &stats);
- }
-
- int SetLayers(size_t num_layers, vsoc_hwc_layer* layers) {
+ int SetLayers(size_t num_layers, cvd_hwc_layer* layers) {
stats_keeper_.RecordSetStart();
return composer_.SetLayers(num_layers, layers);
}
@@ -186,9 +210,14 @@
stats_keeper_.SynchronizedDump(buff, buff_len);
}
+ void FinalizeStatsAndGet(CompositionStats* stats) {
+ stats_keeper_.RecordSetEnd();
+ stats_keeper_.GetLastCompositionStats(&stats);
+ }
+
private:
- StatsKeeper stats_keeper_;
Composer composer_;
+ StatsKeeper stats_keeper_;
};
} // namespace cvd
diff --git a/guest/hals/hwcomposer/cutf_cvm/Android.bp b/guest/hals/hwcomposer/cutf_cvm/Android.bp
index f77486b..3835765 100644
--- a/guest/hals/hwcomposer/cutf_cvm/Android.bp
+++ b/guest/hals/hwcomposer/cutf_cvm/Android.bp
@@ -19,16 +19,17 @@
defaults: ["cuttlefish_guest_only"],
vendor: true,
srcs: [
+ "vsocket_screen_view.cpp",
"hwcomposer.cpp",
- "geometry_utils.cpp",
- "vsoc_composer.cpp",
- "base_composer.cpp",
],
include_dirs: [
"device/google/cuttlefish_common",
],
export_include_dirs: ["."],
- static_libs: ["libyuv_static", "hwcomposer_common"],
+ static_libs: [
+ "libyuv_static",
+ "hwcomposer_common"
+ ],
shared_libs: [
"cuttlefish_auto_resources",
"liblog",
@@ -37,7 +38,6 @@
"libcutils",
"libutils",
"libsync",
- "libhardware",
"libjpeg",
"libcuttlefish_utils",
"libcuttlefish_fs",
diff --git a/guest/hals/hwcomposer/cutf_cvm/base_composer.cpp b/guest/hals/hwcomposer/cutf_cvm/base_composer.cpp
deleted file mode 100644
index da55a95..0000000
--- a/guest/hals/hwcomposer/cutf_cvm/base_composer.cpp
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#include "base_composer.h"
-
-#include <string.h>
-
-#include <cutils/properties.h>
-#include <hardware/gralloc.h>
-#include <log/log.h>
-
-#include <common/libs/device_config/device_config.h>
-#include <common/libs/utils/size_utils.h>
-#include "guest/hals/gralloc/legacy/gralloc_vsoc_priv.h"
-
-namespace cvd {
-
-BaseComposer::BaseComposer(int64_t vsync_base_timestamp)
- : vsync_base_timestamp_(vsync_base_timestamp) {
- vsync_period_ns_ = 1000000000 / frame_buffer_.refresh_rate();
- hw_get_module(GRALLOC_HARDWARE_MODULE_ID,
- reinterpret_cast<const hw_module_t**>(&gralloc_module_));
-}
-
-BaseComposer::~BaseComposer() {}
-
-void BaseComposer::Dump(char* buff __unused, int buff_len __unused) {}
-
-int BaseComposer::PostFrameBufferTarget(buffer_handle_t buffer_handle) {
- int fb_index = frame_buffer_.NextScreenBuffer();
- void* frame_buffer = frame_buffer_.GetBuffer(fb_index);
- const private_handle_t* p_handle =
- reinterpret_cast<const private_handle_t*>(buffer_handle);
- void* buffer;
- int retval = gralloc_module_->lock(gralloc_module_, buffer_handle,
- GRALLOC_USAGE_SW_READ_OFTEN, 0, 0,
- p_handle->x_res, p_handle->y_res, &buffer);
- if (retval != 0) {
- ALOGE("Got error code %d from lock function", retval);
- return -1;
- }
- memcpy(frame_buffer, buffer, frame_buffer_.buffer_size());
- frame_buffer_.Broadcast(fb_index);
- return 0;
-} // namespace cvd
-
-int BaseComposer::PrepareLayers(size_t num_layers, vsoc_hwc_layer* layers) {
- // find unsupported overlays
- for (size_t i = 0; i < num_layers; i++) {
- if (IS_TARGET_FRAMEBUFFER(layers[i].compositionType)) {
- continue;
- }
- layers[i].compositionType = HWC_FRAMEBUFFER;
- }
- return 0;
-}
-
-int BaseComposer::SetLayers(size_t num_layers, vsoc_hwc_layer* layers) {
- for (size_t idx = 0; idx < num_layers; idx++) {
- if (IS_TARGET_FRAMEBUFFER(layers[idx].compositionType)) {
- return PostFrameBufferTarget(layers[idx].handle);
- }
- }
- return -1;
-}
-
-FrameBuffer::FrameBuffer()
- : broadcast_thread_([this]() { BroadcastLoop(); }) {
- GetScreenParameters();
- // inner_buffer needs to be initialized after the final values of the screen
- // parameters are set (either from the config server or default).
- inner_buffer_ = std::vector<char>(buffer_size() * 8);
-}
-
-FrameBuffer::~FrameBuffer() {
- running_ = false;
- broadcast_thread_.join();
-}
-
-int FrameBuffer::NextScreenBuffer() {
- int num_buffers = inner_buffer_.size() / buffer_size();
- last_frame_buffer_ =
- num_buffers > 0 ? (last_frame_buffer_ + 1) % num_buffers : -1;
- return last_frame_buffer_;
-}
-
-void FrameBuffer::GetScreenParameters() {
- auto device_config = cvd::DeviceConfig::Get();
- if (!device_config) {
- LOG(INFO) << "Failed to obtain device configuration from server, running in"
- << " headless mode";
- // It is impossible to ensure host and guest agree on the screen parameters
- // if these could not be read from the host configuration server. It's best
- // to not attempt to send frames in this case.
- running_ = false;
- // Do a phony Broadcast to ensure the broadcaster thread exits.
- Broadcast(-1);
- return;
- }
- x_res_ = device_config->screen_x_res();
- y_res_ = device_config->screen_y_res();
- dpi_ = device_config->screen_dpi();
- refresh_rate_ = device_config->screen_refresh_rate();
-}
-
-bool FrameBuffer::ConnectToScreenServer() {
- auto vsock_frames_port = property_get_int32("ro.boot.vsock_frames_port", -1);
- if (vsock_frames_port <= 0) {
- LOG(INFO) << "No screen server configured, operating on headless mode";
- return false;
- }
-
- screen_server_ = cvd::SharedFD::VsockClient(2, vsock_frames_port,
- SOCK_STREAM);
- if (!screen_server_->IsOpen()) {
- LOG(ERROR) << "Unable to connect to screen server: "
- << screen_server_->StrError();
- return false;
- }
-
- return true;
-}
-
-void FrameBuffer::BroadcastLoop() {
- auto connected = ConnectToScreenServer();
- if (!connected) {
- LOG(ERROR) << "Broadcaster thread exiting due to no connection to screen"
- << " server. Compositions will occur, but frames won't be sent"
- << " anywhere";
- return;
- }
- int32_t current_seq = 0;
- int32_t current_offset;
- LOG(INFO) << "Broadcaster thread loop starting";
- while (true) {
- {
- std::unique_lock<std::mutex> lock(mutex_);
- while (running_ && current_seq == current_seq_) {
- cond_var_.wait(lock);
- }
- if (!running_) {
- LOG(INFO) << "Broadcaster thread exiting";
- return;
- }
- current_offset = current_offset_;
- current_seq = current_seq_;
- }
- int32_t size = buffer_size();
- screen_server_->Write(&size, sizeof(size));
- auto buff = static_cast<char*>(GetBuffer(current_offset));
- while (size > 0) {
- auto written = screen_server_->Write(buff, size);
- size -= written;
- buff += written;
- }
- }
-}
-
-void FrameBuffer::Broadcast(int32_t offset) {
- std::lock_guard<std::mutex> lock(mutex_);
- current_offset_ = offset;
- current_seq_++;
- cond_var_.notify_all();
-}
-void* FrameBuffer::GetBuffer(int fb_index) {
- return &inner_buffer_[buffer_size() * fb_index];
-}
-size_t FrameBuffer::buffer_size() {
- return (line_length() * y_res()) + 4;
-}
-int32_t FrameBuffer::x_res() { return x_res_; }
-int32_t FrameBuffer::y_res() { return y_res_; }
-int32_t FrameBuffer::line_length() {
- return cvd::AlignToPowerOf2(x_res() * bytes_per_pixel(), 4);
-}
-int32_t FrameBuffer::bytes_per_pixel() { return 4; }
-int32_t FrameBuffer::dpi() { return dpi_; }
-int32_t FrameBuffer::refresh_rate() { return refresh_rate_; }
-
-} // namespace cvd
diff --git a/guest/hals/hwcomposer/cutf_cvm/base_composer.h b/guest/hals/hwcomposer/cutf_cvm/base_composer.h
deleted file mode 100644
index fef1eee..0000000
--- a/guest/hals/hwcomposer/cutf_cvm/base_composer.h
+++ /dev/null
@@ -1,100 +0,0 @@
-#pragma once
-/*
- * Copyright (C) 2016 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.
- */
-
-#include <functional>
-#include <mutex>
-#include <thread>
-#include <vector>
-
-#include <hardware/gralloc.h>
-#include <common/libs/fs/shared_fd.h>
-#include "hwcomposer.h"
-
-namespace cvd {
-
-class FrameBuffer{
- public:
- FrameBuffer();
- ~FrameBuffer();
-
- void Broadcast(int32_t offset);
- int NextScreenBuffer();
- void* GetBuffer(int fb_index);
- size_t buffer_size();
- int32_t x_res();
- int32_t y_res();
- int32_t line_length();
- int32_t bytes_per_pixel();
- int32_t dpi();
- int32_t refresh_rate();
- private:
- bool ConnectToScreenServer();
- void GetScreenParameters();
- void BroadcastLoop();
-
- std::vector<char> inner_buffer_;
- int last_frame_buffer_ = 0;
- cvd::SharedFD screen_server_;
- std::thread broadcast_thread_;
- int32_t current_offset_ = 0;
- int32_t current_seq_ = 0;
- std::mutex mutex_;
- std::condition_variable cond_var_;
- bool running_ = true;
- int32_t x_res_{720};
- int32_t y_res_{1280};
- int32_t dpi_{160};
- int32_t refresh_rate_{60};
-};
-
-class BaseComposer {
- public:
- BaseComposer(int64_t vsync_base_timestamp);
- ~BaseComposer();
-
- // Sets the composition type of each layer and returns the number of layers
- // to be composited by the hwcomposer.
- int PrepareLayers(size_t num_layers, vsoc_hwc_layer* layers);
- // Returns 0 if successful.
- int SetLayers(size_t num_layers, vsoc_hwc_layer* layers);
- void Dump(char* buff, int buff_len);
-
- int32_t x_res() {
- return frame_buffer_.x_res();
- }
- int32_t y_res() {
- return frame_buffer_.y_res();
- }
- int32_t dpi() {
- return frame_buffer_.dpi();
- }
- int32_t refresh_rate() {
- return frame_buffer_.refresh_rate();
- }
-
- protected:
- const gralloc_module_t* gralloc_module_;
- int64_t vsync_base_timestamp_;
- int32_t vsync_period_ns_;
- FrameBuffer frame_buffer_;
-
- private:
- // Returns buffer offset or negative on error.
- int PostFrameBufferTarget(buffer_handle_t handle);
-};
-
-} // namespace cvd
diff --git a/guest/hals/hwcomposer/cutf_cvm/hwcomposer.cpp b/guest/hals/hwcomposer/cutf_cvm/hwcomposer.cpp
index 3db7f80..976a68c 100644
--- a/guest/hals/hwcomposer/cutf_cvm/hwcomposer.cpp
+++ b/guest/hals/hwcomposer/cutf_cvm/hwcomposer.cpp
@@ -14,470 +14,39 @@
* limitations under the License.
*/
-// Versions of hwcomposer we implement:
-// JB: 0.3
-// JB-MR1 to N : 1.1
-// N-MR1 to ... : We report 1.1 but SurfaceFlinger has the option to use an
-// adapter to treat our 1.1 hwcomposer as a 2.0. If SF stops using that adapter
-// to support 1.1 implementations it can be copied into cuttlefish from
-// frameworks/native/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.*
+#define LOG_TAG "hwc.cutf_cvm"
-#define LOG_TAG "hwc.cf_x86"
-
-#include <guest/libs/platform_support/api_level_fixes.h>
-
-#include <errno.h>
-#include <fcntl.h>
-#include <math.h>
-#include <poll.h>
-#include <pthread.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <sys/ioctl.h>
-#include <sys/mman.h>
-#include <sys/resource.h>
-#include <sys/time.h>
-
-#include <string>
-
-#define HWC_REMOVE_DEPRECATED_VERSIONS 1
-
-#include <cutils/compiler.h>
-#include <log/log.h>
#include <cutils/properties.h>
-#include <hardware/gralloc.h>
#include <hardware/hardware.h>
#include <hardware/hwcomposer.h>
#include <hardware/hwcomposer_defs.h>
-#include <utils/String8.h>
-#include <utils/Vector.h>
+#include <log/log.h>
-#include "guest/hals/gralloc/legacy/gralloc_vsoc_priv.h"
#include "guest/hals/hwcomposer/common/hwcomposer.h"
-#include <sync/sync.h>
-#include "base_composer.h"
-#include "geometry_utils.h"
-#include "hwcomposer.h"
-#include "vsoc_composer.h"
+#include "guest/hals/hwcomposer/cutf_cvm/vsocket_screen_view.h"
-#ifdef USE_OLD_HWCOMPOSER
-typedef cvd::BaseComposer InnerComposerType;
-#else
-typedef cvd::VSoCComposer InnerComposerType;
-#endif
-
-typedef InnerComposerType ComposerType;
-
-struct vsoc_hwc_composer_device_1_t {
- vsoc_hwc_device base;
- cvd::hwc_composer_device_data_t vsync_data;
- ComposerType* composer;
-};
-
-namespace {
-
-std::string CompositionString(int type) {
- switch (type) {
- case HWC_FRAMEBUFFER:
- return "Framebuffer";
- case HWC_OVERLAY:
- return "Overlay";
- case HWC_BACKGROUND:
- return "Background";
- case HWC_FRAMEBUFFER_TARGET:
- return "FramebufferTarget";
-#if VSOC_PLATFORM_SDK_AFTER(K)
- case HWC_SIDEBAND:
- return "Sideband";
- case HWC_CURSOR_OVERLAY:
- return "CursorOverlay";
-#endif
- default:
- return std::string("Unknown (") + std::to_string(type) + ")";
- }
-}
-
-void LogLayers(int num_layers, vsoc_hwc_layer* layers, int invalid) {
- ALOGE("Layers:");
- for (int idx = 0; idx < num_layers; ++idx) {
- std::string log_line;
- if (idx == invalid) {
- log_line = "Invalid layer: ";
- }
- log_line +=
- "Composition Type: " + CompositionString(layers[idx].compositionType);
- ALOGE("%s", log_line.c_str());
- }
-}
-
-// Ensures that the layer does not include any inconsistencies
-bool IsValidLayer(const vsoc_hwc_layer& layer) {
- if (layer.flags & HWC_SKIP_LAYER) {
- // A layer we are asked to skip validate should not be marked as skip
- ALOGE("%s: Layer is marked as skip", __FUNCTION__);
- return false;
- }
- // Check displayFrame
- if (layer.displayFrame.left > layer.displayFrame.right ||
- layer.displayFrame.top > layer.displayFrame.bottom) {
- ALOGE(
- "%s: Malformed rectangle (displayFrame): [left = %d, right = %d, top = "
- "%d, bottom = %d]",
- __FUNCTION__, layer.displayFrame.left, layer.displayFrame.right,
- layer.displayFrame.top, layer.displayFrame.bottom);
- return false;
- }
- // Validate the handle
- if (private_handle_t::validate(layer.handle) != 0) {
- ALOGE("%s: Layer contains an invalid gralloc handle.", __FUNCTION__);
- return false;
- }
- const private_handle_t* p_handle =
- reinterpret_cast<const private_handle_t*>(layer.handle);
- // Check sourceCrop
- if (layer.sourceCrop.left > layer.sourceCrop.right ||
- layer.sourceCrop.top > layer.sourceCrop.bottom) {
- ALOGE(
- "%s: Malformed rectangle (sourceCrop): [left = %d, right = %d, top = "
- "%d, bottom = %d]",
- __FUNCTION__, layer.sourceCrop.left, layer.sourceCrop.right,
- layer.sourceCrop.top, layer.sourceCrop.bottom);
- return false;
- }
- if (layer.sourceCrop.left < 0 || layer.sourceCrop.top < 0 ||
- layer.sourceCrop.right > p_handle->x_res ||
- layer.sourceCrop.bottom > p_handle->y_res) {
- ALOGE(
- "%s: Invalid sourceCrop for buffer handle: sourceCrop = [left = %d, "
- "right = %d, top = %d, bottom = %d], handle = [width = %d, height = "
- "%d]",
- __FUNCTION__, layer.sourceCrop.left, layer.sourceCrop.right,
- layer.sourceCrop.top, layer.sourceCrop.bottom, p_handle->x_res,
- p_handle->y_res);
- return false;
- }
- return true;
-}
-
-bool IsValidComposition(int num_layers, vsoc_hwc_layer* layers, bool on_set) {
- if (num_layers == 0) {
- ALOGE("Composition requested with 0 layers");
- return false;
- }
- // Sometimes the hwcomposer receives a prepare and set calls with no other
- // layer than the FRAMEBUFFER_TARGET with a null handler. We treat this case
- // independently as a valid composition, but issue a warning about it.
- if (num_layers == 1 && layers[0].compositionType == HWC_FRAMEBUFFER_TARGET &&
- layers[0].handle == NULL) {
- ALOGW("Received request for empty composition, treating as valid noop");
- return true;
- }
- // The FRAMEBUFFER_TARGET layer needs to be sane only if
- // there is at least one layer marked HWC_FRAMEBUFFER or if there is no layer
- // marked HWC_OVERLAY (i.e some layers where composed with OpenGL, no layer
- // marked overlay or framebuffer means that surfaceflinger decided to go for
- // OpenGL without asking the hwcomposer first)
- bool check_fb_target = true;
- for (int idx = 0; idx < num_layers; ++idx) {
- if (layers[idx].compositionType == HWC_FRAMEBUFFER) {
- // There is at least one, so it needs to be checked.
- // It may have been set to false before, so ensure it's set to true.
- check_fb_target = true;
- break;
- }
- if (layers[idx].compositionType == HWC_OVERLAY) {
- // At least one overlay, we may not need to.
- check_fb_target = false;
- }
- }
-
- for (int idx = 0; idx < num_layers; ++idx) {
- switch (layers[idx].compositionType) {
- case HWC_FRAMEBUFFER_TARGET:
- // In the call to prepare() the framebuffer target does not have a valid
- // buffer_handle, so we don't validate it yet.
- if (on_set && check_fb_target && !IsValidLayer(layers[idx])) {
- ALOGE("%s: Invalid layer found", __FUNCTION__);
- LogLayers(num_layers, layers, idx);
- return false;
- }
- break;
- case HWC_OVERLAY:
- if (!(layers[idx].flags & HWC_SKIP_LAYER) &&
- !IsValidLayer(layers[idx])) {
- ALOGE("%s: Invalid layer found", __FUNCTION__);
- LogLayers(num_layers, layers, idx);
- return false;
- }
- break;
- }
- }
- return true;
-}
-
-}
-
-#if VSOC_PLATFORM_SDK_BEFORE(J_MR1)
-static int vsoc_hwc_prepare(vsoc_hwc_device* dev, hwc_layer_list_t* list) {
-#else
-static int vsoc_hwc_prepare(vsoc_hwc_device* dev, size_t numDisplays,
- hwc_display_contents_1_t** displays) {
- if (!numDisplays || !displays) return 0;
-
- hwc_display_contents_1_t* list = displays[HWC_DISPLAY_PRIMARY];
-
- if (!list) return 0;
-#endif
- if (!IsValidComposition(list->numHwLayers, &list->hwLayers[0], false)) {
- LOG_ALWAYS_FATAL("%s: Invalid composition requested", __FUNCTION__);
+static int hwc_open(const struct hw_module_t* module, const char* name,
+ struct hw_device_t** device) {
+ std::unique_ptr<cvd::ScreenView> screen_view(new cvd::VsocketScreenView());
+ if (!screen_view) {
+ ALOGE("Failed to instantiate screen view");
return -1;
}
- reinterpret_cast<vsoc_hwc_composer_device_1_t*>(dev)->composer->PrepareLayers(
- list->numHwLayers, &list->hwLayers[0]);
- return 0;
+
+ return cvd::cvd_hwc_open(std::move(screen_view), module, name, device);
}
-#if VSOC_PLATFORM_SDK_BEFORE(J_MR1)
-int vsoc_hwc_set(struct hwc_composer_device* dev, hwc_display_t dpy,
- hwc_surface_t sur, hwc_layer_list_t* list) {
- if (list->numHwLayers == 1 &&
- layers[0].compositionType == HWC_FRAMEBUFFER_TARGET) {
- ALOGW("Received request for empty composition, treating as valid noop");
- return 0;
- }
- if (!IsValidComposition(list->numHwLayers, &list->hwLayers[0], true)) {
- LOG_ALWAYS_FATAL("%s: Invalid composition requested", __FUNCTION__);
- return -1;
- }
- return reinterpret_cast<vsoc_hwc_composer_device_1_t*>(dev)
- ->composer->SetLayers(list->numHwLayers, &list->hwLayers[0]);
-}
-#else
-static int vsoc_hwc_set(vsoc_hwc_device* dev, size_t numDisplays,
- hwc_display_contents_1_t** displays) {
- if (!numDisplays || !displays) return 0;
-
- hwc_display_contents_1_t* contents = displays[HWC_DISPLAY_PRIMARY];
- if (!contents) return 0;
-
- vsoc_hwc_layer* layers = &contents->hwLayers[0];
- if (contents->numHwLayers == 1 &&
- layers[0].compositionType == HWC_FRAMEBUFFER_TARGET) {
- ALOGW("Received request for empty composition, treating as valid noop");
- return 0;
- }
- if (!IsValidComposition(contents->numHwLayers, layers, true)) {
- LOG_ALWAYS_FATAL("%s: Invalid composition requested", __FUNCTION__);
- return -1;
- }
- int retval =
- reinterpret_cast<vsoc_hwc_composer_device_1_t*>(dev)->composer->SetLayers(
- contents->numHwLayers, layers);
-
- int closedFds = 0;
- for (size_t index = 0; index < contents->numHwLayers; ++index) {
- if (layers[index].acquireFenceFd != -1) {
- close(layers[index].acquireFenceFd);
- layers[index].acquireFenceFd = -1;
- ++closedFds;
- }
- }
- if (closedFds) {
- ALOGI("Saw %zu layers, closed=%d", contents->numHwLayers, closedFds);
- }
-
- // TODO(ghartman): This should be set before returning. On the next set it
- // should be signalled when we load the new frame.
- contents->retireFenceFd = -1;
- return retval;
-}
-#endif
-
-static void vsoc_hwc_register_procs(vsoc_hwc_device* dev,
- const hwc_procs_t* procs) {
- struct vsoc_hwc_composer_device_1_t* pdev =
- (struct vsoc_hwc_composer_device_1_t*)dev;
- pdev->vsync_data.procs = procs;
-}
-
-static int vsoc_hwc_query(vsoc_hwc_device* dev, int what, int* value) {
- struct vsoc_hwc_composer_device_1_t* pdev =
- (struct vsoc_hwc_composer_device_1_t*)dev;
-
- switch (what) {
- case HWC_BACKGROUND_LAYER_SUPPORTED:
- // we support the background layer
- value[0] = 0;
- break;
- case HWC_VSYNC_PERIOD:
- value[0] = pdev->vsync_data.vsync_period_ns;
- break;
- default:
- // unsupported query
- ALOGE("%s badness unsupported query what=%d", __FUNCTION__, what);
- return -EINVAL;
- }
- return 0;
-}
-
-static int vsoc_hwc_event_control(
-#if VSOC_PLATFORM_SDK_BEFORE(J_MR1)
- vsoc_hwc_device* /*dev*/, int event, int /*enabled*/) {
-#else
- vsoc_hwc_device* /*dev*/, int /*dpy*/, int event, int /*enabled*/) {
-#endif
-
- if (event == HWC_EVENT_VSYNC) {
- return 0;
- }
- return -EINVAL;
-}
-
-static int vsoc_hwc_blank(vsoc_hwc_device* /*dev*/, int disp, int /*blank*/) {
- if (!IS_PRIMARY_DISPLAY(disp)) return -EINVAL;
- return 0;
-}
-
-static void vsoc_hwc_dump(vsoc_hwc_device* dev, char* buff, int buff_len) {
- reinterpret_cast<vsoc_hwc_composer_device_1_t*>(dev)->composer->Dump(
- buff, buff_len);
-}
-
-static int vsoc_hwc_get_display_configs(vsoc_hwc_device* /*dev*/, int disp,
- uint32_t* configs, size_t* numConfigs) {
- if (*numConfigs == 0) return 0;
-
- if (IS_PRIMARY_DISPLAY(disp)) {
- configs[0] = 0;
- *numConfigs = 1;
- return 0;
- }
-
- return -EINVAL;
-}
-
-#if VSOC_PLATFORM_SDK_AFTER(J)
-static int32_t vsoc_hwc_attribute(struct vsoc_hwc_composer_device_1_t* pdev,
- const uint32_t attribute) {
- switch (attribute) {
- case HWC_DISPLAY_VSYNC_PERIOD:
- return pdev->vsync_data.vsync_period_ns;
- case HWC_DISPLAY_WIDTH:
- return pdev->composer->x_res();
- case HWC_DISPLAY_HEIGHT:
- return pdev->composer->y_res();
- case HWC_DISPLAY_DPI_X:
- ALOGI("Reporting DPI_X of %d", pdev->composer->dpi());
- // The number of pixels per thousand inches
- return pdev->composer->dpi() * 1000;
- case HWC_DISPLAY_DPI_Y:
- ALOGI("Reporting DPI_Y of %d", pdev->composer->dpi());
- // The number of pixels per thousand inches
- return pdev->composer->dpi() * 1000;
- default:
- ALOGE("unknown display attribute %u", attribute);
- return -EINVAL;
- }
-}
-
-static int vsoc_hwc_get_display_attributes(vsoc_hwc_device* dev, int disp,
- uint32_t config __unused,
- const uint32_t* attributes,
- int32_t* values) {
- struct vsoc_hwc_composer_device_1_t* pdev =
- (struct vsoc_hwc_composer_device_1_t*)dev;
-
- if (!IS_PRIMARY_DISPLAY(disp)) {
- ALOGE("unknown display type %u", disp);
- return -EINVAL;
- }
-
- for (int i = 0; attributes[i] != HWC_DISPLAY_NO_ATTRIBUTE; i++) {
- values[i] = vsoc_hwc_attribute(pdev, attributes[i]);
- }
-
- return 0;
-}
-#endif
-
-static int vsoc_hwc_close(hw_device_t* device) {
- struct vsoc_hwc_composer_device_1_t* dev =
- (struct vsoc_hwc_composer_device_1_t*)device;
- ALOGE("vsoc_hwc_close");
- pthread_kill(dev->vsync_data.vsync_thread, SIGTERM);
- pthread_join(dev->vsync_data.vsync_thread, NULL);
- delete dev->composer;
- delete dev;
- return 0;
-}
-
-static int vsoc_hwc_open(const struct hw_module_t* module, const char* name,
- struct hw_device_t** device) {
- ALOGI("%s", __FUNCTION__);
- if (strcmp(name, HWC_HARDWARE_COMPOSER)) {
- ALOGE("%s called with bad name %s", __FUNCTION__, name);
- return -EINVAL;
- }
-
- vsoc_hwc_composer_device_1_t* dev = new vsoc_hwc_composer_device_1_t();
- if (!dev) {
- ALOGE("%s failed to allocate dev", __FUNCTION__);
- return -ENOMEM;
- }
-
- struct timespec rt;
- if (clock_gettime(CLOCK_MONOTONIC, &rt) == -1) {
- ALOGE("%s:%d error in vsync thread clock_gettime: %s", __FILE__, __LINE__,
- strerror(errno));
- }
- dev->vsync_data.vsync_base_timestamp = int64_t(rt.tv_sec) * 1e9 + rt.tv_nsec;
-
- dev->base.common.tag = HARDWARE_DEVICE_TAG;
- dev->base.common.version = VSOC_HWC_DEVICE_API_VERSION;
- dev->base.common.module = const_cast<hw_module_t*>(module);
- dev->base.common.close = vsoc_hwc_close;
-
- dev->base.prepare = vsoc_hwc_prepare;
- dev->base.set = vsoc_hwc_set;
- dev->base.query = vsoc_hwc_query;
- dev->base.registerProcs = vsoc_hwc_register_procs;
- dev->base.dump = vsoc_hwc_dump;
-#if VSOC_PLATFORM_SDK_BEFORE(J_MR1)
- static hwc_methods_t hwc_methods = {vsoc_hwc_event_control};
- dev->base.methods = &hwc_methods;
-#else
- dev->base.blank = vsoc_hwc_blank;
- dev->base.eventControl = vsoc_hwc_event_control;
- dev->base.getDisplayConfigs = vsoc_hwc_get_display_configs;
- dev->base.getDisplayAttributes = vsoc_hwc_get_display_attributes;
-#endif
- dev->composer = new ComposerType(dev->vsync_data.vsync_base_timestamp);
- dev->vsync_data.vsync_period_ns = 1000000000 / dev->composer->refresh_rate();
- int ret = pthread_create(&dev->vsync_data.vsync_thread,
- NULL, cvd::hwc_vsync_thread, &dev->vsync_data);
- if (ret) {
- ALOGE("failed to start vsync thread: %s", strerror(ret));
- ret = -ret;
- delete dev;
- } else {
- *device = &dev->base.common;
- }
-
- return ret;
-}
-
-static struct hw_module_methods_t vsoc_hwc_module_methods = {
- vsoc_hwc_open,
+static struct hw_module_methods_t hwc_module_methods = {
+ hwc_open,
};
hwc_module_t HAL_MODULE_INFO_SYM = {{HARDWARE_MODULE_TAG,
HWC_MODULE_API_VERSION_0_1,
HARDWARE_HAL_API_VERSION,
HWC_HARDWARE_MODULE_ID,
- "VSOC hwcomposer module",
+ "VSOCKET hwcomposer module",
"Google",
- &vsoc_hwc_module_methods,
+ &hwc_module_methods,
NULL,
{0}}};
diff --git a/guest/hals/hwcomposer/cutf_cvm/hwcomposer.h b/guest/hals/hwcomposer/cutf_cvm/hwcomposer.h
deleted file mode 100644
index a6b8121..0000000
--- a/guest/hals/hwcomposer/cutf_cvm/hwcomposer.h
+++ /dev/null
@@ -1,35 +0,0 @@
-#pragma once
-/*
- * Copyright (C) 2016 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.
- */
-
-#include <guest/libs/platform_support/api_level_fixes.h>
-
-#include <hardware/hwcomposer.h>
-#include <hardware/hwcomposer_defs.h>
-
-#if VSOC_PLATFORM_SDK_BEFORE(J_MR1)
-typedef hwc_composer_device_t vsoc_hwc_device;
-typedef hwc_layer_t vsoc_hwc_layer;
-#define IS_TARGET_FRAMEBUFFER(x) false
-#define IS_PRIMARY_DISPLAY(x) true
-#define VSOC_HWC_DEVICE_API_VERSION HWC_DEVICE_API_VERSION_0_3
-#else
-typedef hwc_composer_device_1_t vsoc_hwc_device;
-typedef hwc_layer_1_t vsoc_hwc_layer;
-#define IS_TARGET_FRAMEBUFFER(x) ((x) == HWC_FRAMEBUFFER_TARGET)
-#define IS_PRIMARY_DISPLAY(x) ((x) == HWC_DISPLAY_PRIMARY)
-#define VSOC_HWC_DEVICE_API_VERSION HWC_DEVICE_API_VERSION_1_1
-#endif
diff --git a/guest/hals/hwcomposer/cutf_cvm/vsoc_composer.h b/guest/hals/hwcomposer/cutf_cvm/vsoc_composer.h
deleted file mode 100644
index 7007931..0000000
--- a/guest/hals/hwcomposer/cutf_cvm/vsoc_composer.h
+++ /dev/null
@@ -1,48 +0,0 @@
-#pragma once
-/*
- * Copyright (C) 2016 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.
- */
-
-#include <vector>
-
-#include <hardware/gralloc.h>
-
-#include "guest/hals/gralloc/legacy/gralloc_vsoc_priv.h"
-
-#include "base_composer.h"
-#include "hwcomposer.h"
-
-namespace cvd {
-
-class VSoCComposer : public BaseComposer {
- public:
- VSoCComposer(int64_t vsync_base_timestamp);
- ~VSoCComposer();
-
- // override
- int PrepareLayers(size_t num_layers, vsoc_hwc_layer* layers);
- // override
- int SetLayers(size_t num_layers, vsoc_hwc_layer* layers);
-
- protected:
- static const int kNumTmpBufferPieces;
- uint8_t* RotateTmpBuffer(unsigned int order);
- uint8_t* GetSpecialTmpBuffer(size_t needed_size);
- void CompositeLayer(vsoc_hwc_layer* src_layer, int32_t fb_offset);
- std::vector<uint8_t> tmp_buffer_;
- std::vector<uint8_t> special_tmp_buffer_;
-};
-
-} // namespace cvd
diff --git a/guest/hals/hwcomposer/cutf_cvm/vsocket_screen_view.cpp b/guest/hals/hwcomposer/cutf_cvm/vsocket_screen_view.cpp
new file mode 100644
index 0000000..2e2683f
--- /dev/null
+++ b/guest/hals/hwcomposer/cutf_cvm/vsocket_screen_view.cpp
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include "guest/hals/hwcomposer/cutf_cvm/vsocket_screen_view.h"
+
+#include <cutils/properties.h>
+#include <log/log.h>
+
+#include "common/libs/device_config/device_config.h"
+
+namespace cvd {
+
+VsocketScreenView::VsocketScreenView()
+ : broadcast_thread_([this]() { BroadcastLoop(); }) {
+ GetScreenParameters();
+ // inner_buffer needs to be initialized after the final values of the screen
+ // parameters are set (either from the config server or default).
+ inner_buffer_ = std::vector<char>(buffer_size() * 8);
+}
+
+VsocketScreenView::~VsocketScreenView() {
+ running_ = false;
+ broadcast_thread_.join();
+}
+
+void VsocketScreenView::GetScreenParameters() {
+ auto device_config = cvd::DeviceConfig::Get();
+ if (!device_config) {
+ ALOGI(
+ "Failed to obtain device configuration from server, running in "
+ "headless mode");
+ // It is impossible to ensure host and guest agree on the screen parameters
+ // if these could not be read from the host configuration server. It's best
+ // to not attempt to send frames in this case.
+ running_ = false;
+ // Do a phony Broadcast to ensure the broadcaster thread exits.
+ Broadcast(-1);
+ return;
+ }
+ x_res_ = device_config->screen_x_res();
+ y_res_ = device_config->screen_y_res();
+ dpi_ = device_config->screen_dpi();
+ refresh_rate_ = device_config->screen_refresh_rate();
+}
+
+bool VsocketScreenView::ConnectToScreenServer() {
+ auto vsock_frames_port = property_get_int32("ro.boot.vsock_frames_port", -1);
+ if (vsock_frames_port <= 0) {
+ ALOGI("No screen server configured, operating on headless mode");
+ return false;
+ }
+
+ screen_server_ =
+ cvd::SharedFD::VsockClient(2, vsock_frames_port, SOCK_STREAM);
+ if (!screen_server_->IsOpen()) {
+ ALOGE("Unable to connect to screen server: %s", screen_server_->StrError());
+ return false;
+ }
+
+ return true;
+}
+
+void VsocketScreenView::BroadcastLoop() {
+ auto connected = ConnectToScreenServer();
+ if (!connected) {
+ ALOGE(
+ "Broadcaster thread exiting due to no connection to screen server. "
+ "Compositions will occur, but frames won't be sent anywhere");
+ return;
+ }
+ int current_seq = 0;
+ int current_offset;
+ ALOGI("Broadcaster thread loop starting");
+ while (true) {
+ {
+ std::unique_lock<std::mutex> lock(mutex_);
+ while (running_ && current_seq == current_seq_) {
+ cond_var_.wait(lock);
+ }
+ if (!running_) {
+ ALOGI("Broadcaster thread exiting");
+ return;
+ }
+ current_offset = current_offset_;
+ current_seq = current_seq_;
+ }
+ int32_t size = buffer_size();
+ screen_server_->Write(&size, sizeof(size));
+ auto buff = static_cast<char*>(GetBuffer(current_offset));
+ while (size > 0) {
+ auto written = screen_server_->Write(buff, size);
+ size -= written;
+ buff += written;
+ }
+ }
+}
+
+void VsocketScreenView::Broadcast(int offset, const CompositionStats*) {
+ std::lock_guard<std::mutex> lock(mutex_);
+ current_offset_ = offset;
+ current_seq_++;
+ cond_var_.notify_all();
+}
+
+void* VsocketScreenView::GetBuffer(int buffer_id) {
+ return &inner_buffer_[buffer_size() * buffer_id];
+}
+
+int32_t VsocketScreenView::x_res() const { return x_res_; }
+int32_t VsocketScreenView::y_res() const { return y_res_; }
+int32_t VsocketScreenView::dpi() const { return dpi_; }
+int32_t VsocketScreenView::refresh_rate() const { return refresh_rate_; }
+
+int VsocketScreenView::num_buffers() const {
+ return inner_buffer_.size() / buffer_size();
+}
+
+} // namespace cvd
diff --git a/guest/hals/hwcomposer/cutf_cvm/vsocket_screen_view.h b/guest/hals/hwcomposer/cutf_cvm/vsocket_screen_view.h
new file mode 100644
index 0000000..0d6d90a
--- /dev/null
+++ b/guest/hals/hwcomposer/cutf_cvm/vsocket_screen_view.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+#pragma once
+
+#include <condition_variable>
+#include <functional>
+#include <mutex>
+#include <thread>
+#include <vector>
+
+#include "common/libs/fs/shared_fd.h"
+#include "guest/hals/hwcomposer/common/screen_view.h"
+
+namespace cvd {
+
+class VsocketScreenView : public ScreenView {
+ public:
+ VsocketScreenView();
+ virtual ~VsocketScreenView();
+
+ void Broadcast(int buffer_id,
+ const CompositionStats* stats = nullptr) override;
+ void* GetBuffer(int fb_index) override;
+
+ int32_t x_res() const override;
+ int32_t y_res() const override;
+ int32_t dpi() const override;
+ int32_t refresh_rate() const override;
+
+ int num_buffers() const override;
+
+ private:
+ bool ConnectToScreenServer();
+ void GetScreenParameters();
+ void BroadcastLoop();
+
+ std::vector<char> inner_buffer_;
+ cvd::SharedFD screen_server_;
+ std::thread broadcast_thread_;
+ int current_offset_ = 0;
+ int current_seq_ = 0;
+ std::mutex mutex_;
+ std::condition_variable cond_var_;
+ bool running_ = true;
+ int32_t x_res_{720};
+ int32_t y_res_{1280};
+ int32_t dpi_{160};
+ int32_t refresh_rate_{60};
+};
+
+} // namespace cvd
diff --git a/guest/hals/hwcomposer/vsoc-future/hwcomposer.cpp b/guest/hals/hwcomposer/vsoc-future/hwcomposer.cpp
index fdeef65..f18712c 100644
--- a/guest/hals/hwcomposer/vsoc-future/hwcomposer.cpp
+++ b/guest/hals/hwcomposer/vsoc-future/hwcomposer.cpp
@@ -181,8 +181,7 @@
const vsoc_buffer_handle_t* fb_handle =
reinterpret_cast<const vsoc_buffer_handle_t*>(
list->hwLayers[i].handle);
- ScreenRegionView::GetInstance()->BroadcastNewFrame(
- fb_handle->offset);
+ ScreenRegionView::GetInstance()->BroadcastNewFrame(fb_handle->offset);
break;
}
}
@@ -273,7 +272,6 @@
int hwc_getDisplayAttributes(struct hwc_composer_device_1* /*dev*/, int disp,
uint32_t /*config*/, const uint32_t* attributes,
int32_t* values) {
-
if (disp != HWC_DISPLAY_PRIMARY) {
ALOGE("Unknown display type %u", disp);
return -EINVAL;
diff --git a/guest/hals/hwcomposer/vsoc/Android.bp b/guest/hals/hwcomposer/vsoc/Android.bp
new file mode 100644
index 0000000..559a1c1
--- /dev/null
+++ b/guest/hals/hwcomposer/vsoc/Android.bp
@@ -0,0 +1,47 @@
+// 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.
+
+
+cc_library_shared {
+ name: "hwcomposer.cutf_ivsh_ashmem",
+ relative_install_path: "hw",
+ defaults: ["cuttlefish_guest_only"],
+ cflags: [
+ "-DGATHER_STATS",
+ // Uncomment the following line to revert to GL compositions
+ // "-DUSE_OLD_HWCOMPOSER",
+ ],
+ srcs: [
+ "vsoc_screen_view.cpp",
+ "hwcomposer.cpp",
+ ],
+ export_include_dirs: ["."],
+ static_libs: [
+ "libyuv_static",
+ "hwcomposer_common"
+ ],
+ shared_libs: [
+ "cuttlefish_auto_resources",
+ "liblog",
+ "libhardware",
+ "libbase",
+ "libcutils",
+ "libutils",
+ "libsync",
+ "libjpeg",
+ "libcuttlefish_utils",
+ "libcuttlefish_fs",
+ "vsoc_lib",
+ ],
+}
diff --git a/guest/hals/hwcomposer/vsoc/Android.mk b/guest/hals/hwcomposer/vsoc/Android.mk
deleted file mode 100644
index b7cb911..0000000
--- a/guest/hals/hwcomposer/vsoc/Android.mk
+++ /dev/null
@@ -1,44 +0,0 @@
-# Copyright (C) 2016 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.
-
-LOCAL_PATH := $(call my-dir)
-
-# HAL module implemenation stored in
-# hw/<OVERLAY_HARDWARE_MODULE_ID>.<ro.product.board>.so
-
-# Old hwcomposer, relies on GLES composition
-include $(CLEAR_VARS)
-include $(LOCAL_PATH)/hwcomposer.mk
-LOCAL_CFLAGS += -DUSE_OLD_HWCOMPOSER -Wall -Werror
-LOCAL_MODULE := hwcomposer.cutf_ivsh-deprecated
-
-# See b/67109557
-ifeq (true, $(TARGET_TRANSLATE_2ND_ARCH))
-LOCAL_MULTILIB := first
-endif
-
-include $(BUILD_SHARED_LIBRARY)
-
-# New hwcomposer, performs software composition
-include $(CLEAR_VARS)
-include $(LOCAL_PATH)/hwcomposer.mk
-LOCAL_MODULE := hwcomposer.cutf_ivsh_ashmem
-LOCAL_VENDOR_MODULE := true
-
-# See b/67109557
-ifeq (true, $(TARGET_TRANSLATE_2ND_ARCH))
-LOCAL_MULTILIB := first
-endif
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/guest/hals/hwcomposer/vsoc/base_composer.cpp b/guest/hals/hwcomposer/vsoc/base_composer.cpp
deleted file mode 100644
index 986d241..0000000
--- a/guest/hals/hwcomposer/vsoc/base_composer.cpp
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#include "base_composer.h"
-
-#include <string.h>
-
-#include <log/log.h>
-#include <hardware/gralloc.h>
-
-#include "common/vsoc/lib/screen_region_view.h"
-#include "guest/hals/gralloc/legacy/gralloc_vsoc_priv.h"
-
-using vsoc::screen::ScreenRegionView;
-
-namespace cvd {
-
-namespace {
-
-void BroadcastFrameBufferChanged(int index) {
- ScreenRegionView::GetInstance()->BroadcastNewFrame(
- static_cast<uint32_t>(index));
-}
-
-} // namespace
-
-BaseComposer::BaseComposer(int64_t vsync_base_timestamp,
- int32_t vsync_period_ns)
- : vsync_base_timestamp_(vsync_base_timestamp),
- vsync_period_ns_(vsync_period_ns),
- fb_broadcaster_(BroadcastFrameBufferChanged) {
- hw_get_module(GRALLOC_HARDWARE_MODULE_ID,
- reinterpret_cast<const hw_module_t**>(&gralloc_module_));
-}
-
-BaseComposer::~BaseComposer() {}
-
-FbBroadcaster BaseComposer::ReplaceFbBroadcaster(FbBroadcaster fb_broadcaster) {
- FbBroadcaster tmp = fb_broadcaster_;
- fb_broadcaster_ = fb_broadcaster;
- return tmp;
-}
-
-void BaseComposer::Dump(char* buff __unused, int buff_len __unused) {}
-
-void BaseComposer::Broadcast(int fb_index) {
- fb_broadcaster_(fb_index);
-}
-
-int BaseComposer::PostFrameBufferTarget(buffer_handle_t buffer_handle) {
- int fb_index = NextScreenBuffer();
- if (fb_index < 0) {
- ALOGE("Could not get the next buffer. Is the screen region large enough?");
- return -1;
- }
- auto screen_view = ScreenRegionView::GetInstance();
- void* frame_buffer = screen_view->GetBuffer(fb_index);
- const private_handle_t* p_handle =
- reinterpret_cast<const private_handle_t*>(buffer_handle);
- void* buffer;
- int retval = gralloc_module_->lock(gralloc_module_, buffer_handle,
- GRALLOC_USAGE_SW_READ_OFTEN, 0, 0,
- p_handle->x_res, p_handle->y_res, &buffer);
- if (retval != 0) {
- ALOGE("Got error code %d from lock function", retval);
- return -1;
- }
- memcpy(frame_buffer, buffer, screen_view->buffer_size());
- Broadcast(fb_index);
- return 0;
-} // namespace cvd
-
-int BaseComposer::PrepareLayers(size_t num_layers, vsoc_hwc_layer* layers) {
- // find unsupported overlays
- for (size_t i = 0; i < num_layers; i++) {
- if (IS_TARGET_FRAMEBUFFER(layers[i].compositionType)) {
- continue;
- }
- layers[i].compositionType = HWC_FRAMEBUFFER;
- }
- return 0;
-}
-
-int BaseComposer::SetLayers(size_t num_layers, vsoc_hwc_layer* layers) {
- for (size_t idx = 0; idx < num_layers; idx++) {
- if (IS_TARGET_FRAMEBUFFER(layers[idx].compositionType)) {
- return PostFrameBufferTarget(layers[idx].handle);
- }
- }
- return -1;
-}
-
-int BaseComposer::NextScreenBuffer() {
- int num_buffers = ScreenRegionView::GetInstance()->number_of_buffers();
- last_frame_buffer_ =
- num_buffers > 0 ? (last_frame_buffer_ + 1) % num_buffers : -1;
- return last_frame_buffer_;
-}
-
-} // namespace cvd
diff --git a/guest/hals/hwcomposer/vsoc/base_composer.h b/guest/hals/hwcomposer/vsoc/base_composer.h
deleted file mode 100644
index f3467ef..0000000
--- a/guest/hals/hwcomposer/vsoc/base_composer.h
+++ /dev/null
@@ -1,59 +0,0 @@
-#pragma once
-/*
- * Copyright (C) 2016 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.
- */
-
-#include <functional>
-
-#include <hardware/gralloc.h>
-#include "hwcomposer.h"
-
-namespace cvd {
-
-using FbBroadcaster = std::function<void(int)>;
-
-class BaseComposer {
- public:
- BaseComposer(int64_t vsync_base_timestamp, int32_t vsync_period_ns);
- ~BaseComposer();
-
- // Sets the composition type of each layer and returns the number of layers
- // to be composited by the hwcomposer.
- int PrepareLayers(size_t num_layers, vsoc_hwc_layer* layers);
- // Returns 0 if successful.
- int SetLayers(size_t num_layers, vsoc_hwc_layer* layers);
- // Changes the broadcaster, gives the ability to report more than just the
- // offset by using a wrapper like the StatsKeepingComposer. Returns the old
- // broadcaster. Passing a NULL pointer will cause the composer to not
- // broadcast at all.
- FbBroadcaster ReplaceFbBroadcaster(FbBroadcaster);
- void Dump(char* buff, int buff_len);
-
- protected:
- void Broadcast(int32_t offset);
- int NextScreenBuffer();
-
- const gralloc_module_t* gralloc_module_;
- int64_t vsync_base_timestamp_;
- int32_t vsync_period_ns_;
- int last_frame_buffer_ = -1; // The first index will be 0
-
- private:
- // Returns buffer offset or negative on error.
- int PostFrameBufferTarget(buffer_handle_t handle);
- FbBroadcaster fb_broadcaster_;
-};
-
-} // namespace cvd
diff --git a/guest/hals/hwcomposer/vsoc/geometry_utils.cpp b/guest/hals/hwcomposer/vsoc/geometry_utils.cpp
deleted file mode 100644
index 75b7a61..0000000
--- a/guest/hals/hwcomposer/vsoc/geometry_utils.cpp
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#include "geometry_utils.h"
-#include <algorithm>
-#include <utility>
-
-namespace cvd {
-
-bool LayersOverlap(const vsoc_hwc_layer& layer1, const vsoc_hwc_layer& layer2) {
- int left1 = layer1.displayFrame.left;
- int right1 = layer1.displayFrame.right;
- int top1 = layer1.displayFrame.top;
- int bottom1 = layer1.displayFrame.bottom;
-
- int left2 = layer2.displayFrame.left;
- int right2 = layer2.displayFrame.right;
- int top2 = layer2.displayFrame.top;
- int bottom2 = layer2.displayFrame.bottom;
-
- bool overlap_x = left1 < right2 && left2 < right1;
- bool overlap_y = top1 < bottom2 && top2 < bottom1;
-
- return overlap_x && overlap_y;
-}
-
-} // namespace cvd
diff --git a/guest/hals/hwcomposer/vsoc/geometry_utils.h b/guest/hals/hwcomposer/vsoc/geometry_utils.h
deleted file mode 100644
index 937283f..0000000
--- a/guest/hals/hwcomposer/vsoc/geometry_utils.h
+++ /dev/null
@@ -1,24 +0,0 @@
-#pragma once
-/*
- * Copyright (C) 2016 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.
- */
-
-#include "hwcomposer.h"
-
-namespace cvd {
-
-bool LayersOverlap(const vsoc_hwc_layer& layer1, const vsoc_hwc_layer& layer2);
-
-} // namespace cvd
diff --git a/guest/hals/hwcomposer/vsoc/hwcomposer.cpp b/guest/hals/hwcomposer/vsoc/hwcomposer.cpp
index 2aaedd9..67713f2 100644
--- a/guest/hals/hwcomposer/vsoc/hwcomposer.cpp
+++ b/guest/hals/hwcomposer/vsoc/hwcomposer.cpp
@@ -14,481 +14,39 @@
* limitations under the License.
*/
-// Versions of hwcomposer we implement:
-// JB: 0.3
-// JB-MR1 to N : 1.1
-// N-MR1 to ... : We report 1.1 but SurfaceFlinger has the option to use an
-// adapter to treat our 1.1 hwcomposer as a 2.0. If SF stops using that adapter
-// to support 1.1 implementations it can be copied into cuttlefish from
-// frameworks/native/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.*
+#define LOG_TAG "hwc.cutf_cvm"
-#define LOG_TAG "hwc.cf_x86"
-
-#include <guest/libs/platform_support/api_level_fixes.h>
-
-#include <errno.h>
-#include <fcntl.h>
-#include <math.h>
-#include <poll.h>
-#include <pthread.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <sys/ioctl.h>
-#include <sys/mman.h>
-#include <sys/resource.h>
-#include <sys/time.h>
-
-#include <string>
-
-#define HWC_REMOVE_DEPRECATED_VERSIONS 1
-
-#include <cutils/compiler.h>
-#include <log/log.h>
#include <cutils/properties.h>
-#include <hardware/gralloc.h>
#include <hardware/hardware.h>
#include <hardware/hwcomposer.h>
#include <hardware/hwcomposer_defs.h>
-#include <utils/String8.h>
-#include <utils/Vector.h>
+#include <log/log.h>
-#include "common/vsoc/lib/screen_region_view.h"
-#include "guest/hals/gralloc/legacy/gralloc_vsoc_priv.h"
#include "guest/hals/hwcomposer/common/hwcomposer.h"
-#include <sync/sync.h>
-#include "base_composer.h"
-#include "geometry_utils.h"
-#include "hwcomposer.h"
-#include "stats_keeper.h"
-#include "vsoc_composer.h"
+#include "guest/hals/hwcomposer/vsoc/vsoc_screen_view.h"
-using vsoc::screen::ScreenRegionView;
-
-#ifdef USE_OLD_HWCOMPOSER
-typedef cvd::BaseComposer InnerComposerType;
-#else
-typedef cvd::VSoCComposer InnerComposerType;
-#endif
-
-#ifdef GATHER_STATS
-typedef cvd::StatsKeepingComposer<InnerComposerType> ComposerType;
-#else
-typedef InnerComposerType ComposerType;
-#endif
-
-struct vsoc_hwc_composer_device_1_t {
- vsoc_hwc_device base;
- cvd::hwc_composer_device_data_t vsync_data;
- ComposerType* composer;
-};
-
-namespace {
-
-std::string CompositionString(int type) {
- switch (type) {
- case HWC_FRAMEBUFFER:
- return "Framebuffer";
- case HWC_OVERLAY:
- return "Overlay";
- case HWC_BACKGROUND:
- return "Background";
- case HWC_FRAMEBUFFER_TARGET:
- return "FramebufferTarget";
-#if VSOC_PLATFORM_SDK_AFTER(K)
- case HWC_SIDEBAND:
- return "Sideband";
- case HWC_CURSOR_OVERLAY:
- return "CursorOverlay";
-#endif
- default:
- return std::string("Unknown (") + std::to_string(type) + ")";
- }
-}
-
-void LogLayers(int num_layers, vsoc_hwc_layer* layers, int invalid) {
- ALOGE("Layers:");
- for (int idx = 0; idx < num_layers; ++idx) {
- std::string log_line;
- if (idx == invalid) {
- log_line = "Invalid layer: ";
- }
- log_line +=
- "Composition Type: " + CompositionString(layers[idx].compositionType);
- ALOGE("%s", log_line.c_str());
- }
-}
-
-// Ensures that the layer does not include any inconsistencies
-bool IsValidLayer(const vsoc_hwc_layer& layer) {
- if (layer.flags & HWC_SKIP_LAYER) {
- // A layer we are asked to skip validate should not be marked as skip
- ALOGE("%s: Layer is marked as skip", __FUNCTION__);
- return false;
- }
- // Check displayFrame
- if (layer.displayFrame.left > layer.displayFrame.right ||
- layer.displayFrame.top > layer.displayFrame.bottom) {
- ALOGE(
- "%s: Malformed rectangle (displayFrame): [left = %d, right = %d, top = "
- "%d, bottom = %d]",
- __FUNCTION__, layer.displayFrame.left, layer.displayFrame.right,
- layer.displayFrame.top, layer.displayFrame.bottom);
- return false;
- }
- // Validate the handle
- if (private_handle_t::validate(layer.handle) != 0) {
- ALOGE("%s: Layer contains an invalid gralloc handle.", __FUNCTION__);
- return false;
- }
- const private_handle_t* p_handle =
- reinterpret_cast<const private_handle_t*>(layer.handle);
- // Check sourceCrop
- if (layer.sourceCrop.left > layer.sourceCrop.right ||
- layer.sourceCrop.top > layer.sourceCrop.bottom) {
- ALOGE(
- "%s: Malformed rectangle (sourceCrop): [left = %d, right = %d, top = "
- "%d, bottom = %d]",
- __FUNCTION__, layer.sourceCrop.left, layer.sourceCrop.right,
- layer.sourceCrop.top, layer.sourceCrop.bottom);
- return false;
- }
- if (layer.sourceCrop.left < 0 || layer.sourceCrop.top < 0 ||
- layer.sourceCrop.right > p_handle->x_res ||
- layer.sourceCrop.bottom > p_handle->y_res) {
- ALOGE(
- "%s: Invalid sourceCrop for buffer handle: sourceCrop = [left = %d, "
- "right = %d, top = %d, bottom = %d], handle = [width = %d, height = "
- "%d]",
- __FUNCTION__, layer.sourceCrop.left, layer.sourceCrop.right,
- layer.sourceCrop.top, layer.sourceCrop.bottom, p_handle->x_res,
- p_handle->y_res);
- return false;
- }
- return true;
-}
-
-bool IsValidComposition(int num_layers, vsoc_hwc_layer* layers, bool on_set) {
- if (num_layers == 0) {
- ALOGE("Composition requested with 0 layers");
- return false;
- }
- // Sometimes the hwcomposer receives a prepare and set calls with no other
- // layer than the FRAMEBUFFER_TARGET with a null handler. We treat this case
- // independently as a valid composition, but issue a warning about it.
- if (num_layers == 1 && layers[0].compositionType == HWC_FRAMEBUFFER_TARGET &&
- layers[0].handle == NULL) {
- ALOGW("Received request for empty composition, treating as valid noop");
- return true;
- }
- // The FRAMEBUFFER_TARGET layer needs to be sane only if
- // there is at least one layer marked HWC_FRAMEBUFFER or if there is no layer
- // marked HWC_OVERLAY (i.e some layers where composed with OpenGL, no layer
- // marked overlay or framebuffer means that surfaceflinger decided to go for
- // OpenGL without asking the hwcomposer first)
- bool check_fb_target = true;
- for (int idx = 0; idx < num_layers; ++idx) {
- if (layers[idx].compositionType == HWC_FRAMEBUFFER) {
- // There is at least one, so it needs to be checked.
- // It may have been set to false before, so ensure it's set to true.
- check_fb_target = true;
- break;
- }
- if (layers[idx].compositionType == HWC_OVERLAY) {
- // At least one overlay, we may not need to.
- check_fb_target = false;
- }
- }
-
- for (int idx = 0; idx < num_layers; ++idx) {
- switch (layers[idx].compositionType) {
- case HWC_FRAMEBUFFER_TARGET:
- // In the call to prepare() the framebuffer target does not have a valid
- // buffer_handle, so we don't validate it yet.
- if (on_set && check_fb_target && !IsValidLayer(layers[idx])) {
- ALOGE("%s: Invalid layer found", __FUNCTION__);
- LogLayers(num_layers, layers, idx);
- return false;
- }
- break;
- case HWC_OVERLAY:
- if (!(layers[idx].flags & HWC_SKIP_LAYER) &&
- !IsValidLayer(layers[idx])) {
- ALOGE("%s: Invalid layer found", __FUNCTION__);
- LogLayers(num_layers, layers, idx);
- return false;
- }
- break;
- }
- }
- return true;
-}
-
-}
-
-#if VSOC_PLATFORM_SDK_BEFORE(J_MR1)
-static int vsoc_hwc_prepare(vsoc_hwc_device* dev, hwc_layer_list_t* list) {
-#else
-static int vsoc_hwc_prepare(vsoc_hwc_device* dev, size_t numDisplays,
- hwc_display_contents_1_t** displays) {
- if (!numDisplays || !displays) return 0;
-
- hwc_display_contents_1_t* list = displays[HWC_DISPLAY_PRIMARY];
-
- if (!list) return 0;
-#endif
- if (!IsValidComposition(list->numHwLayers, &list->hwLayers[0], false)) {
- LOG_ALWAYS_FATAL("%s: Invalid composition requested", __FUNCTION__);
+static int hwc_open(const struct hw_module_t* module, const char* name,
+ struct hw_device_t** device) {
+ std::unique_ptr<cvd::ScreenView> screen_view(new cvd::VSoCScreenView());
+ if (!screen_view) {
+ ALOGE("Failed to instantiate screen view");
return -1;
}
- reinterpret_cast<vsoc_hwc_composer_device_1_t*>(dev)->composer->PrepareLayers(
- list->numHwLayers, &list->hwLayers[0]);
- return 0;
+
+ return cvd::cvd_hwc_open(std::move(screen_view), module, name, device);
}
-#if VSOC_PLATFORM_SDK_BEFORE(J_MR1)
-int vsoc_hwc_set(struct hwc_composer_device* dev, hwc_display_t dpy,
- hwc_surface_t sur, hwc_layer_list_t* list) {
- if (list->numHwLayers == 1 &&
- layers[0].compositionType == HWC_FRAMEBUFFER_TARGET) {
- ALOGW("Received request for empty composition, treating as valid noop");
- return 0;
- }
- if (!IsValidComposition(list->numHwLayers, &list->hwLayers[0], true)) {
- LOG_ALWAYS_FATAL("%s: Invalid composition requested", __FUNCTION__);
- return -1;
- }
- return reinterpret_cast<vsoc_hwc_composer_device_1_t*>(dev)
- ->composer->SetLayers(list->numHwLayers, &list->hwLayers[0]);
-}
-#else
-static int vsoc_hwc_set(vsoc_hwc_device* dev, size_t numDisplays,
- hwc_display_contents_1_t** displays) {
- if (!numDisplays || !displays) return 0;
-
- hwc_display_contents_1_t* contents = displays[HWC_DISPLAY_PRIMARY];
- if (!contents) return 0;
-
- vsoc_hwc_layer* layers = &contents->hwLayers[0];
- if (contents->numHwLayers == 1 &&
- layers[0].compositionType == HWC_FRAMEBUFFER_TARGET) {
- ALOGW("Received request for empty composition, treating as valid noop");
- return 0;
- }
- if (!IsValidComposition(contents->numHwLayers, layers, true)) {
- LOG_ALWAYS_FATAL("%s: Invalid composition requested", __FUNCTION__);
- return -1;
- }
- int retval =
- reinterpret_cast<vsoc_hwc_composer_device_1_t*>(dev)->composer->SetLayers(
- contents->numHwLayers, layers);
-
- int closedFds = 0;
- for (size_t index = 0; index < contents->numHwLayers; ++index) {
- if (layers[index].acquireFenceFd != -1) {
- close(layers[index].acquireFenceFd);
- layers[index].acquireFenceFd = -1;
- ++closedFds;
- }
- }
- if (closedFds) {
- ALOGI("Saw %zu layers, closed=%d", contents->numHwLayers, closedFds);
- }
-
- // TODO(ghartman): This should be set before returning. On the next set it
- // should be signalled when we load the new frame.
- contents->retireFenceFd = -1;
- return retval;
-}
-#endif
-
-static void vsoc_hwc_register_procs(vsoc_hwc_device* dev,
- const hwc_procs_t* procs) {
- struct vsoc_hwc_composer_device_1_t* pdev =
- (struct vsoc_hwc_composer_device_1_t*)dev;
- pdev->vsync_data.procs = procs;
-}
-
-static int vsoc_hwc_query(vsoc_hwc_device* dev, int what, int* value) {
- struct vsoc_hwc_composer_device_1_t* pdev =
- (struct vsoc_hwc_composer_device_1_t*)dev;
-
- switch (what) {
- case HWC_BACKGROUND_LAYER_SUPPORTED:
- // we support the background layer
- value[0] = 0;
- break;
- case HWC_VSYNC_PERIOD:
- value[0] = pdev->vsync_data.vsync_period_ns;
- break;
- default:
- // unsupported query
- ALOGE("%s badness unsupported query what=%d", __FUNCTION__, what);
- return -EINVAL;
- }
- return 0;
-}
-
-static int vsoc_hwc_event_control(
-#if VSOC_PLATFORM_SDK_BEFORE(J_MR1)
- vsoc_hwc_device* /*dev*/, int event, int /*enabled*/) {
-#else
- vsoc_hwc_device* /*dev*/, int /*dpy*/, int event, int /*enabled*/) {
-#endif
-
- if (event == HWC_EVENT_VSYNC) {
- return 0;
- }
- return -EINVAL;
-}
-
-static int vsoc_hwc_blank(vsoc_hwc_device* /*dev*/, int disp, int /*blank*/) {
- if (!IS_PRIMARY_DISPLAY(disp)) return -EINVAL;
- return 0;
-}
-
-static void vsoc_hwc_dump(vsoc_hwc_device* dev, char* buff, int buff_len) {
- reinterpret_cast<vsoc_hwc_composer_device_1_t*>(dev)->composer->Dump(
- buff, buff_len);
-}
-
-static int vsoc_hwc_get_display_configs(vsoc_hwc_device* /*dev*/, int disp,
- uint32_t* configs, size_t* numConfigs) {
- if (*numConfigs == 0) return 0;
-
- if (IS_PRIMARY_DISPLAY(disp)) {
- configs[0] = 0;
- *numConfigs = 1;
- return 0;
- }
-
- return -EINVAL;
-}
-
-#if VSOC_PLATFORM_SDK_AFTER(J)
-static int32_t vsoc_hwc_attribute(struct vsoc_hwc_composer_device_1_t* pdev,
- const uint32_t attribute) {
- auto screen_view = ScreenRegionView::GetInstance();
- switch (attribute) {
- case HWC_DISPLAY_VSYNC_PERIOD:
- return pdev->vsync_data.vsync_period_ns;
- case HWC_DISPLAY_WIDTH:
- return screen_view->x_res();
- case HWC_DISPLAY_HEIGHT:
- return screen_view->y_res();
- case HWC_DISPLAY_DPI_X:
- ALOGI("Reporting DPI_X of %d", screen_view->dpi());
- // The number of pixels per thousand inches
- return screen_view->dpi() * 1000;
- case HWC_DISPLAY_DPI_Y:
- ALOGI("Reporting DPI_Y of %d", screen_view->dpi());
- // The number of pixels per thousand inches
- return screen_view->dpi() * 1000;
- default:
- ALOGE("unknown display attribute %u", attribute);
- return -EINVAL;
- }
-}
-
-static int vsoc_hwc_get_display_attributes(vsoc_hwc_device* dev, int disp,
- uint32_t config __unused,
- const uint32_t* attributes,
- int32_t* values) {
- struct vsoc_hwc_composer_device_1_t* pdev =
- (struct vsoc_hwc_composer_device_1_t*)dev;
-
- if (!IS_PRIMARY_DISPLAY(disp)) {
- ALOGE("unknown display type %u", disp);
- return -EINVAL;
- }
-
- for (int i = 0; attributes[i] != HWC_DISPLAY_NO_ATTRIBUTE; i++) {
- values[i] = vsoc_hwc_attribute(pdev, attributes[i]);
- }
-
- return 0;
-}
-#endif
-
-static int vsoc_hwc_close(hw_device_t* device) {
- struct vsoc_hwc_composer_device_1_t* dev =
- (struct vsoc_hwc_composer_device_1_t*)device;
- ALOGE("vsoc_hwc_close");
- pthread_kill(dev->vsync_data.vsync_thread, SIGTERM);
- pthread_join(dev->vsync_data.vsync_thread, NULL);
- delete dev->composer;
- delete dev;
- return 0;
-}
-
-static int vsoc_hwc_open(const struct hw_module_t* module, const char* name,
- struct hw_device_t** device) {
- ALOGI("%s", __FUNCTION__);
- if (strcmp(name, HWC_HARDWARE_COMPOSER)) {
- ALOGE("%s called with bad name %s", __FUNCTION__, name);
- return -EINVAL;
- }
-
- vsoc_hwc_composer_device_1_t* dev = new vsoc_hwc_composer_device_1_t();
- if (!dev) {
- ALOGE("%s failed to allocate dev", __FUNCTION__);
- return -ENOMEM;
- }
-
- int refreshRate = ScreenRegionView::GetInstance()->refresh_rate_hz();
- dev->vsync_data.vsync_period_ns = 1000000000 / refreshRate;
- struct timespec rt;
- if (clock_gettime(CLOCK_MONOTONIC, &rt) == -1) {
- LOG_ALWAYS_FATAL("%s:%d error in vsync thread clock_gettime: %s", __FILE__,
- __LINE__, strerror(errno));
- }
- dev->vsync_data.vsync_base_timestamp = int64_t(rt.tv_sec) * 1e9 + rt.tv_nsec;
-
- dev->base.common.tag = HARDWARE_DEVICE_TAG;
- dev->base.common.version = VSOC_HWC_DEVICE_API_VERSION;
- dev->base.common.module = const_cast<hw_module_t*>(module);
- dev->base.common.close = vsoc_hwc_close;
-
- dev->base.prepare = vsoc_hwc_prepare;
- dev->base.set = vsoc_hwc_set;
- dev->base.query = vsoc_hwc_query;
- dev->base.registerProcs = vsoc_hwc_register_procs;
- dev->base.dump = vsoc_hwc_dump;
-#if VSOC_PLATFORM_SDK_BEFORE(J_MR1)
- static hwc_methods_t hwc_methods = {vsoc_hwc_event_control};
- dev->base.methods = &hwc_methods;
-#else
- dev->base.blank = vsoc_hwc_blank;
- dev->base.eventControl = vsoc_hwc_event_control;
- dev->base.getDisplayConfigs = vsoc_hwc_get_display_configs;
- dev->base.getDisplayAttributes = vsoc_hwc_get_display_attributes;
-#endif
- dev->composer =
- new ComposerType(dev->vsync_data.vsync_base_timestamp, dev->vsync_data.vsync_period_ns);
-
- int ret = pthread_create(&dev->vsync_data.vsync_thread, NULL, cvd::hwc_vsync_thread, &dev->vsync_data);
- if (ret) {
- ALOGE("failed to start vsync thread: %s", strerror(ret));
- ret = -ret;
- delete dev;
- } else {
- *device = &dev->base.common;
- }
-
- return ret;
-}
-
-static struct hw_module_methods_t vsoc_hwc_module_methods = {
- vsoc_hwc_open,
+static struct hw_module_methods_t hwc_module_methods = {
+ hwc_open,
};
hwc_module_t HAL_MODULE_INFO_SYM = {{HARDWARE_MODULE_TAG,
HWC_MODULE_API_VERSION_0_1,
HARDWARE_HAL_API_VERSION,
HWC_HARDWARE_MODULE_ID,
- "VSOC hwcomposer module",
+ "VSoC hwcomposer module",
"Google",
- &vsoc_hwc_module_methods,
+ &hwc_module_methods,
NULL,
{0}}};
diff --git a/guest/hals/hwcomposer/vsoc/hwcomposer.h b/guest/hals/hwcomposer/vsoc/hwcomposer.h
deleted file mode 100644
index a6b8121..0000000
--- a/guest/hals/hwcomposer/vsoc/hwcomposer.h
+++ /dev/null
@@ -1,35 +0,0 @@
-#pragma once
-/*
- * Copyright (C) 2016 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.
- */
-
-#include <guest/libs/platform_support/api_level_fixes.h>
-
-#include <hardware/hwcomposer.h>
-#include <hardware/hwcomposer_defs.h>
-
-#if VSOC_PLATFORM_SDK_BEFORE(J_MR1)
-typedef hwc_composer_device_t vsoc_hwc_device;
-typedef hwc_layer_t vsoc_hwc_layer;
-#define IS_TARGET_FRAMEBUFFER(x) false
-#define IS_PRIMARY_DISPLAY(x) true
-#define VSOC_HWC_DEVICE_API_VERSION HWC_DEVICE_API_VERSION_0_3
-#else
-typedef hwc_composer_device_1_t vsoc_hwc_device;
-typedef hwc_layer_1_t vsoc_hwc_layer;
-#define IS_TARGET_FRAMEBUFFER(x) ((x) == HWC_FRAMEBUFFER_TARGET)
-#define IS_PRIMARY_DISPLAY(x) ((x) == HWC_DISPLAY_PRIMARY)
-#define VSOC_HWC_DEVICE_API_VERSION HWC_DEVICE_API_VERSION_1_1
-#endif
diff --git a/guest/hals/hwcomposer/vsoc/hwcomposer.mk b/guest/hals/hwcomposer/vsoc/hwcomposer.mk
deleted file mode 100644
index cb27c95..0000000
--- a/guest/hals/hwcomposer/vsoc/hwcomposer.mk
+++ /dev/null
@@ -1,57 +0,0 @@
-# Copyright (C) 2016 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.
-
-
-ifeq (0, $(shell test $(PLATFORM_SDK_VERSION) -ge 21; echo $$?))
-LOCAL_MODULE_RELATIVE_PATH := hw
-else
-LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
-endif
-LOCAL_MULTILIB := first
-LOCAL_MODULE_TAGS := optional
-LOCAL_VENDOR_MODULE := true
-
-LOCAL_SHARED_LIBRARIES := \
- libbase \
- liblog \
- libcutils \
- libutils \
- libsync \
- libhardware \
- libjpeg \
- vsoc_lib \
- $(VSOC_STLPORT_LIBS)
-
-LOCAL_STATIC_LIBRARIES := \
- libyuv_static \
- hwcomposer_common \
-
-LOCAL_SRC_FILES := \
- geometry_utils.cpp \
- hwcomposer.cpp \
- vsoc_composer.cpp \
- stats_keeper.cpp \
- base_composer.cpp \
-
-LOCAL_CFLAGS += \
- -DGATHER_STATS \
- $(VSOC_VERSION_CFLAGS) \
- -Wall -Werror
-
-LOCAL_C_INCLUDES := \
- device/google/cuttlefish_common \
- device/google/cuttlefish_kernel \
- external/libyuv/files/include \
- bionic \
- $(VSOC_STLPORT_INCLUDES)
diff --git a/guest/hals/hwcomposer/vsoc/vsoc_composer.cpp b/guest/hals/hwcomposer/vsoc/vsoc_composer.cpp
deleted file mode 100644
index d77c004..0000000
--- a/guest/hals/hwcomposer/vsoc/vsoc_composer.cpp
+++ /dev/null
@@ -1,612 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#include "vsoc_composer.h"
-
-#include <algorithm>
-#include <cstdlib>
-#include <utility>
-#include <vector>
-
-#include <log/log.h>
-#include <hardware/hwcomposer.h>
-#include <hardware/hwcomposer_defs.h>
-#include <libyuv.h>
-#include <system/graphics.h>
-
-#include "common/vsoc/lib/screen_region_view.h"
-
-#include "geometry_utils.h"
-
-using vsoc::screen::ScreenRegionView;
-
-namespace cvd {
-
-namespace {
-
-bool LayerNeedsScaling(const vsoc_hwc_layer& layer) {
- int from_w = layer.sourceCrop.right - layer.sourceCrop.left;
- int from_h = layer.sourceCrop.bottom - layer.sourceCrop.top;
- int to_w = layer.displayFrame.right - layer.displayFrame.left;
- int to_h = layer.displayFrame.bottom - layer.displayFrame.top;
-
- bool not_rot_scale = from_w != to_w || from_h != to_h;
- bool rot_scale = from_w != to_h || from_h != to_w;
-
- bool needs_rot = layer.transform & HAL_TRANSFORM_ROT_90;
-
- return needs_rot ? rot_scale : not_rot_scale;
-}
-
-bool LayerNeedsBlending(const vsoc_hwc_layer& layer) {
- return layer.blending != HWC_BLENDING_NONE;
-}
-
-bool LayerNeedsAttenuation(const vsoc_hwc_layer& layer) {
- return layer.blending == HWC_BLENDING_COVERAGE;
-}
-
-struct BufferSpec;
-typedef int (*ConverterFunction)(const BufferSpec& src, const BufferSpec& dst,
- bool v_flip);
-int DoCopy(const BufferSpec& src, const BufferSpec& dst, bool v_flip);
-int ConvertFromYV12(const BufferSpec& src, const BufferSpec& dst, bool v_flip);
-ConverterFunction GetConverter(uint32_t format) {
- switch (format) {
- case HAL_PIXEL_FORMAT_RGBA_8888:
- case HAL_PIXEL_FORMAT_RGBX_8888:
- case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
- return &DoCopy;
-
- case HAL_PIXEL_FORMAT_YV12:
- return &ConvertFromYV12;
-
- // Unsupported formats
- // TODO(jemoreira): Conversion from these formats should be implemented as
- // we find evidence of its usage.
- // case HAL_PIXEL_FORMAT_BGRA_8888:
-
- // case HAL_PIXEL_FORMAT_RGB_888:
- // case HAL_PIXEL_FORMAT_RGB_565:
-
- // case HAL_PIXEL_FORMAT_sRGB_A_8888:
- // case HAL_PIXEL_FORMAT_sRGB_X_8888:
-
- // case HAL_PIXEL_FORMAT_Y8:
- // case HAL_PIXEL_FORMAT_Y16:
-
- // case HAL_PIXEL_FORMAT_RAW_SENSOR:
- // case HAL_PIXEL_FORMAT_BLOB:
-
- // case HAL_PIXEL_FORMAT_YCbCr_420_888:
- // case HAL_PIXEL_FORMAT_YCbCr_422_SP:
- // case HAL_PIXEL_FORMAT_YCrCb_420_SP:
- // case HAL_PIXEL_FORMAT_YCbCr_422_I:
- default:
- ALOGW("Unsupported format: 0x%04x, returning null converter function",
- format);
- }
- return NULL;
-}
-
-// Whether we support a given format
-bool IsFormatSupported(uint32_t format) { return GetConverter(format) != NULL; }
-
-bool CanCompositeLayer(const vsoc_hwc_layer& layer) {
- if (layer.handle == NULL) {
- ALOGW("%s received a layer with a null handler", __FUNCTION__);
- return false;
- }
- int format = reinterpret_cast<const private_handle_t*>(layer.handle)->format;
- if (!IsFormatSupported(format)) {
- ALOGD("Unsupported pixel format: 0x%x, doing software composition instead",
- format);
- return false;
- }
- return true;
-}
-
-/*******************************************************************************
-Libyuv's convert functions only allow the combination of any rotation (multiple
-of 90 degrees) and a vertical flip, but not horizontal flips.
-Surfaceflinger's transformations are expressed in terms of a vertical flip, a
-horizontal flip and/or a single 90 degrees clockwise rotation (see
-NATIVE_WINDOW_TRANSFORM_HINT documentation on system/window.h for more insight).
-The following code allows to turn a horizontal flip into a 180 degrees rotation
-and a vertical flip.
-*******************************************************************************/
-libyuv::RotationMode GetRotationFromTransform(uint32_t transform) {
- uint32_t rotation =
- (transform & HAL_TRANSFORM_ROT_90) ? 1 : 0; // 1 * ROT90 bit
- rotation += (transform & HAL_TRANSFORM_FLIP_H) ? 2 : 0; // 2 * VFLIP bit
- return static_cast<libyuv::RotationMode>(90 * rotation);
-}
-
-bool GetVFlipFromTransform(uint32_t transform) {
- // vertical flip xor horizontal flip
- return ((transform & HAL_TRANSFORM_FLIP_V) >> 1) ^
- (transform & HAL_TRANSFORM_FLIP_H);
-}
-
-struct BufferSpec {
- uint8_t* buffer;
- size_t size;
- int width;
- int height;
- int stride;
- int crop_x;
- int crop_y;
- int crop_width;
- int crop_height;
- uint32_t format;
-
- BufferSpec(uint8_t* buffer, size_t size, int width, int height, int stride)
- : buffer(buffer),
- size(size),
- width(width),
- height(height),
- stride(stride),
- crop_x(0),
- crop_y(0),
- crop_width(width),
- crop_height(height),
- format(HAL_PIXEL_FORMAT_RGBA_8888) {}
-};
-
-int ConvertFromYV12(const BufferSpec& src, const BufferSpec& dst, bool v_flip) {
- // use the stride in pixels as the source width
- int stride_in_pixels = src.stride / formatToBytesPerPixel(src.format);
-
- // The following calculation of plane offsets and alignments are based on
- // swiftshader's Sampler::setTextureLevel() implementation
- // (Renderer/Sampler.cpp:225)
- uint8_t* src_y = src.buffer;
- int stride_y = stride_in_pixels;
- uint8_t* src_v = src_y + stride_y * src.height;
- int stride_v = ScreenRegionView::align(stride_y / 2);
- uint8_t* src_u = src_v + stride_v * src.height / 2;
- int stride_u = ScreenRegionView::align(stride_y / 2);
-
- // Adjust for crop
- src_y += src.crop_y * stride_y + src.crop_x;
- src_v += (src.crop_y / 2) * stride_v + (src.crop_x / 2);
- src_u += (src.crop_y / 2) * stride_u + (src.crop_x / 2);
- uint8_t* dst_buffer = dst.buffer + dst.crop_y * dst.stride +
- dst.crop_x * formatToBytesPerPixel(dst.format);
-
- // YV12 is the same as I420, with the U and V planes swapped
- return libyuv::I420ToARGB(src_y, stride_y, src_v, stride_v, src_u, stride_u,
- dst_buffer, dst.stride, dst.crop_width,
- v_flip ? -dst.crop_height : dst.crop_height);
-}
-
-int DoConversion(const BufferSpec& src, const BufferSpec& dst, bool v_flip) {
- return (*GetConverter(src.format))(src, dst, v_flip);
-}
-
-int DoCopy(const BufferSpec& src, const BufferSpec& dst, bool v_flip) {
- // Point to the upper left corner of the crop rectangle
- uint8_t* src_buffer = src.buffer + src.crop_y * src.stride +
- src.crop_x * formatToBytesPerPixel(src.format);
- uint8_t* dst_buffer = dst.buffer + dst.crop_y * dst.stride +
- dst.crop_x * formatToBytesPerPixel(dst.format);
- int width = src.crop_width;
- int height = src.crop_height;
-
- if (v_flip) {
- height = -height;
- }
-
- // HAL formats are named based on the order of the pixel componets on the
- // byte stream, while libyuv formats are named based on the order of those
- // pixel components in an integer written from left to right. So
- // libyuv::FOURCC_ARGB is equivalent to HAL_PIXEL_FORMAT_BGRA_8888.
- return libyuv::ARGBCopy(src_buffer, src.stride, dst_buffer, dst.stride, width,
- height);
-}
-
-int DoRotation(const BufferSpec& src, const BufferSpec& dst,
- libyuv::RotationMode rotation, bool v_flip) {
- // Point to the upper left corner of the crop rectangles
- uint8_t* src_buffer = src.buffer + src.crop_y * src.stride +
- src.crop_x * formatToBytesPerPixel(src.format);
- uint8_t* dst_buffer = dst.buffer + dst.crop_y * dst.stride +
- dst.crop_x * formatToBytesPerPixel(dst.format);
- int width = src.crop_width;
- int height = src.crop_height;
-
- if (v_flip) {
- height = -height;
- }
-
- return libyuv::ARGBRotate(src_buffer, src.stride, dst_buffer, dst.stride,
- width, height, rotation);
-}
-
-int DoScaling(const BufferSpec& src, const BufferSpec& dst, bool v_flip) {
- // Point to the upper left corner of the crop rectangles
- uint8_t* src_buffer = src.buffer + src.crop_y * src.stride +
- src.crop_x * formatToBytesPerPixel(src.format);
- uint8_t* dst_buffer = dst.buffer + dst.crop_y * dst.stride +
- dst.crop_x * formatToBytesPerPixel(dst.format);
- int src_width = src.crop_width;
- int src_height = src.crop_height;
- int dst_width = dst.crop_width;
- int dst_height = dst.crop_height;
-
- if (v_flip) {
- src_height = -src_height;
- }
-
- return libyuv::ARGBScale(src_buffer, src.stride, src_width, src_height,
- dst_buffer, dst.stride, dst_width, dst_height,
- libyuv::kFilterBilinear);
-}
-
-int DoAttenuation(const BufferSpec& src, const BufferSpec& dest, bool v_flip) {
- // Point to the upper left corner of the crop rectangles
- uint8_t* src_buffer = src.buffer + src.crop_y * src.stride +
- src.crop_x * formatToBytesPerPixel(src.format);
- uint8_t* dst_buffer = dest.buffer + dest.crop_y * dest.stride +
- dest.crop_x * formatToBytesPerPixel(dest.format);
- int width = dest.crop_width;
- int height = dest.crop_height;
-
- if (v_flip) {
- height = -height;
- }
-
- return libyuv::ARGBAttenuate(src_buffer, src.stride, dst_buffer, dest.stride,
- width, height);
-}
-
-int DoBlending(const BufferSpec& src, const BufferSpec& dest, bool v_flip) {
- // Point to the upper left corner of the crop rectangles
- uint8_t* src_buffer = src.buffer + src.crop_y * src.stride +
- src.crop_x * formatToBytesPerPixel(src.format);
- uint8_t* dst_buffer = dest.buffer + dest.crop_y * dest.stride +
- dest.crop_x * formatToBytesPerPixel(dest.format);
- int width = dest.crop_width;
- int height = dest.crop_height;
-
- if (v_flip) {
- height = -height;
- }
-
- // libyuv's ARGB format is hwcomposer's BGRA format, since blending only cares
- // for the position of alpha in the pixel and not the position of the colors
- // this function is perfectly usable.
- return libyuv::ARGBBlend(src_buffer, src.stride, dst_buffer, dest.stride,
- dst_buffer, dest.stride, width, height);
-}
-
-} // namespace
-
-void VSoCComposer::CompositeLayer(vsoc_hwc_layer* src_layer,
- int buffer_idx) {
- libyuv::RotationMode rotation =
- GetRotationFromTransform(src_layer->transform);
-
- const private_handle_t* src_priv_handle =
- reinterpret_cast<const private_handle_t*>(src_layer->handle);
-
- // TODO(jemoreira): Remove the hardcoded fomat.
- bool needs_conversion = src_priv_handle->format != HAL_PIXEL_FORMAT_RGBX_8888;
- bool needs_scaling = LayerNeedsScaling(*src_layer);
- bool needs_rotation = rotation != libyuv::kRotate0;
- bool needs_transpose = needs_rotation && rotation != libyuv::kRotate180;
- bool needs_vflip = GetVFlipFromTransform(src_layer->transform);
- bool needs_attenuation = LayerNeedsAttenuation(*src_layer);
- bool needs_blending = LayerNeedsBlending(*src_layer);
- bool needs_copy = !(needs_conversion || needs_scaling || needs_rotation ||
- needs_vflip || needs_attenuation || needs_blending);
-
- uint8_t* src_buffer;
- uint8_t* dst_buffer = reinterpret_cast<uint8_t*>(
- ScreenRegionView::GetInstance()->GetBuffer(buffer_idx));
- int retval = gralloc_module_->lock(
- gralloc_module_, src_layer->handle, GRALLOC_USAGE_SW_READ_OFTEN, 0, 0,
- src_priv_handle->x_res, src_priv_handle->y_res,
- reinterpret_cast<void**>(&src_buffer));
- if (retval) {
- ALOGE("Got error code %d from lock function", retval);
- return;
- }
- if (retval) {
- ALOGE("Got error code %d from lock function", retval);
- // TODO(jemoreira): Use a lock_guard-like object.
- gralloc_module_->unlock(gralloc_module_, src_priv_handle);
- return;
- }
-
- BufferSpec src_layer_spec(src_buffer, src_priv_handle->total_size,
- src_priv_handle->x_res, src_priv_handle->y_res,
- src_priv_handle->stride_in_pixels *
- formatToBytesPerPixel(src_priv_handle->format));
- src_layer_spec.crop_x = src_layer->sourceCrop.left;
- src_layer_spec.crop_y = src_layer->sourceCrop.top;
- src_layer_spec.crop_width =
- src_layer->sourceCrop.right - src_layer->sourceCrop.left;
- src_layer_spec.crop_height =
- src_layer->sourceCrop.bottom - src_layer->sourceCrop.top;
- src_layer_spec.format = src_priv_handle->format;
-
- auto screen_view = ScreenRegionView::GetInstance();
- BufferSpec dst_layer_spec(dst_buffer, screen_view->buffer_size(),
- screen_view->x_res(), screen_view->y_res(),
- screen_view->line_length());
- dst_layer_spec.crop_x = src_layer->displayFrame.left;
- dst_layer_spec.crop_y = src_layer->displayFrame.top;
- dst_layer_spec.crop_width =
- src_layer->displayFrame.right - src_layer->displayFrame.left;
- dst_layer_spec.crop_height =
- src_layer->displayFrame.bottom - src_layer->displayFrame.top;
- // TODO(jemoreira): Remove the hardcoded fomat.
- dst_layer_spec.format = HAL_PIXEL_FORMAT_RGBX_8888;
-
- // Add the destination layer to the bottom of the buffer stack
- std::vector<BufferSpec> dest_buffer_stack(1, dst_layer_spec);
-
- // If more than operation is to be performed, a temporary buffer is needed for
- // each additional operation
-
- // N operations need N destination buffers, the destination layer (the
- // framebuffer) is one of them, so only N-1 temporary buffers are needed.
- // Vertical flip is not taken into account because it can be done together
- // with any other operation.
- int needed_tmp_buffers = (needs_conversion ? 1 : 0) +
- (needs_scaling ? 1 : 0) + (needs_rotation ? 1 : 0) +
- (needs_attenuation ? 1 : 0) +
- (needs_blending ? 1 : 0) + (needs_copy ? 1 : 0) - 1;
-
- int x_res = src_layer->displayFrame.right - src_layer->displayFrame.left;
- int y_res = src_layer->displayFrame.bottom - src_layer->displayFrame.top;
- size_t output_frame_size =
- x_res *
- ScreenRegionView::align(y_res * screen_view->bytes_per_pixel());
- while (needed_tmp_buffers > 0) {
- BufferSpec tmp(RotateTmpBuffer(needed_tmp_buffers), output_frame_size,
- x_res, y_res,
- ScreenRegionView::align(
- x_res * screen_view->bytes_per_pixel()));
- dest_buffer_stack.push_back(tmp);
- needed_tmp_buffers--;
- }
-
- // Conversion and scaling should always be the first operations, so that every
- // other operation works on equally sized frames (garanteed to fit in the tmp
- // buffers)
-
- // TODO(jemoreira): We are converting to ARGB as the first step under the
- // assumption that scaling ARGB is faster than scaling I420 (the most common).
- // This should be confirmed with testing.
- if (needs_conversion) {
- BufferSpec& dst_buffer_spec = dest_buffer_stack.back();
- if (needs_scaling || needs_transpose) {
- // If a rotation or a scaling operation are needed the dimensions at the
- // top of the buffer stack are wrong (wrong sizes for scaling, swapped
- // width and height for 90 and 270 rotations).
- // Make width and height match the crop sizes on the source
- int src_width = src_layer_spec.crop_width;
- int src_height = src_layer_spec.crop_height;
- int dst_stride = ScreenRegionView::align(
- src_width * screen_view->bytes_per_pixel());
- size_t needed_size = dst_stride * src_height;
- dst_buffer_spec.width = src_width;
- dst_buffer_spec.height = src_height;
- // Ajust the stride accordingly
- dst_buffer_spec.stride = dst_stride;
- // Crop sizes also need to be adjusted
- dst_buffer_spec.crop_width = src_width;
- dst_buffer_spec.crop_height = src_height;
- dst_buffer_spec.size = needed_size;
- // crop_x and y are fine at 0, format is already set to match destination
-
- // In case of a scale, the source frame may be bigger than the default tmp
- // buffer size
- if (needed_size > tmp_buffer_.size() / kNumTmpBufferPieces) {
- dst_buffer_spec.buffer = GetSpecialTmpBuffer(needed_size);
- }
- }
- retval = DoConversion(src_layer_spec, dst_buffer_spec, needs_vflip);
- if (retval) {
- ALOGE("Got error code %d from DoConversion function", retval);
- }
- needs_vflip = false;
- src_layer_spec = dst_buffer_spec;
- dest_buffer_stack.pop_back();
- }
-
- if (needs_scaling) {
- BufferSpec& dst_buffer_spec = dest_buffer_stack.back();
- if (needs_transpose) {
- // If a rotation is needed, the temporary buffer has the correct size but
- // needs to be transposed and have its stride updated accordingly. The
- // crop sizes also needs to be transposed, but not the x and y since they
- // are both zero in a temporary buffer (and it is a temporary buffer
- // because a rotation will be performed next).
- std::swap(dst_buffer_spec.width, dst_buffer_spec.height);
- std::swap(dst_buffer_spec.crop_width, dst_buffer_spec.crop_height);
- // TODO (jemoreira): Aligment (To align here may cause the needed size to
- // be bigger than the buffer, so care should be taken)
- dst_buffer_spec.stride =
- dst_buffer_spec.width * screen_view->bytes_per_pixel();
- }
- retval = DoScaling(src_layer_spec, dst_buffer_spec, needs_vflip);
- needs_vflip = false;
- if (retval) {
- ALOGE("Got error code %d from DoScaling function", retval);
- }
- src_layer_spec = dst_buffer_spec;
- dest_buffer_stack.pop_back();
- }
-
- if (needs_rotation) {
- retval = DoRotation(src_layer_spec, dest_buffer_stack.back(), rotation,
- needs_vflip);
- needs_vflip = false;
- if (retval) {
- ALOGE("Got error code %d from DoTransform function", retval);
- }
- src_layer_spec = dest_buffer_stack.back();
- dest_buffer_stack.pop_back();
- }
-
- if (needs_attenuation) {
- retval =
- DoAttenuation(src_layer_spec, dest_buffer_stack.back(), needs_vflip);
- needs_vflip = false;
- if (retval) {
- ALOGE("Got error code %d from DoBlending function", retval);
- }
- src_layer_spec = dest_buffer_stack.back();
- dest_buffer_stack.pop_back();
- }
-
- if (needs_copy) {
- retval = DoCopy(src_layer_spec, dest_buffer_stack.back(), needs_vflip);
- needs_vflip = false;
- if (retval) {
- ALOGE("Got error code %d from DoBlending function", retval);
- }
- src_layer_spec = dest_buffer_stack.back();
- dest_buffer_stack.pop_back();
- }
-
- // Blending (if needed) should always be the last operation, so that it reads
- // and writes in the destination layer and not some temporary buffer.
- if (needs_blending) {
- retval = DoBlending(src_layer_spec, dest_buffer_stack.back(), needs_vflip);
- needs_vflip = false;
- if (retval) {
- ALOGE("Got error code %d from DoBlending function", retval);
- }
- // Don't need to assign destination to source in the last one
- dest_buffer_stack.pop_back();
- }
-
- gralloc_module_->unlock(gralloc_module_, src_priv_handle);
-}
-
-/* static */ const int VSoCComposer::kNumTmpBufferPieces = 2;
-
-VSoCComposer::VSoCComposer(int64_t vsync_base_timestamp,
- int32_t vsync_period_ns)
- : BaseComposer(vsync_base_timestamp, vsync_period_ns),
- tmp_buffer_(kNumTmpBufferPieces *
- ScreenRegionView::GetInstance()->buffer_size()) {}
-
-VSoCComposer::~VSoCComposer() {}
-
-int VSoCComposer::PrepareLayers(size_t num_layers, vsoc_hwc_layer* layers) {
- int composited_layers_count = 0;
-
- // Loop over layers in inverse order of z-index
- for (size_t layer_index = num_layers; layer_index > 0;) {
- // Decrement here to be able to compare unsigned integer with 0 in the
- // loop condition
- --layer_index;
- if (IS_TARGET_FRAMEBUFFER(layers[layer_index].compositionType)) {
- continue;
- }
- if (layers[layer_index].flags & HWC_SKIP_LAYER) {
- continue;
- }
- if (layers[layer_index].compositionType == HWC_BACKGROUND) {
- layers[layer_index].compositionType = HWC_FRAMEBUFFER;
- continue;
- }
- layers[layer_index].compositionType = HWC_OVERLAY;
- // Hwcomposer cannot draw below software-composed layers, so we need
- // to mark those HWC_FRAMEBUFFER as well.
- for (size_t top_idx = layer_index + 1; top_idx < num_layers; ++top_idx) {
- // layers marked as skip are in a state that makes them unreliable to
- // read, so it's best to assume they cover the whole screen
- if (layers[top_idx].flags & HWC_SKIP_LAYER ||
- (layers[top_idx].compositionType == HWC_FRAMEBUFFER &&
- LayersOverlap(layers[layer_index], layers[top_idx]))) {
- layers[layer_index].compositionType = HWC_FRAMEBUFFER;
- break;
- }
- }
- if (layers[layer_index].compositionType == HWC_OVERLAY &&
- !CanCompositeLayer(layers[layer_index])) {
- layers[layer_index].compositionType = HWC_FRAMEBUFFER;
- }
- if (layers[layer_index].compositionType == HWC_OVERLAY) {
- ++composited_layers_count;
- }
- }
- return composited_layers_count;
-}
-
-int VSoCComposer::SetLayers(size_t num_layers, vsoc_hwc_layer* layers) {
- int targetFbs = 0;
- int buffer_idx = NextScreenBuffer();
-
- // The framebuffer target layer should be composed if at least one layers was
- // marked HWC_FRAMEBUFFER or if it's the only layer in the composition
- // (unlikely)
- bool fb_target = true;
- for (size_t idx = 0; idx < num_layers; idx++) {
- if (layers[idx].compositionType == HWC_FRAMEBUFFER) {
- // At least one was found
- fb_target = true;
- break;
- }
- if (layers[idx].compositionType == HWC_OVERLAY) {
- // Not the only layer in the composition
- fb_target = false;
- }
- }
-
- // When the framebuffer target needs to be composed, it has to go first.
- if (fb_target) {
- for (size_t idx = 0; idx < num_layers; idx++) {
- if (IS_TARGET_FRAMEBUFFER(layers[idx].compositionType)) {
- CompositeLayer(&layers[idx], buffer_idx);
- break;
- }
- }
- }
-
- for (size_t idx = 0; idx < num_layers; idx++) {
- if (IS_TARGET_FRAMEBUFFER(layers[idx].compositionType)) {
- ++targetFbs;
- }
- if (layers[idx].compositionType == HWC_OVERLAY &&
- !(layers[idx].flags & HWC_SKIP_LAYER)) {
- CompositeLayer(&layers[idx], buffer_idx);
- }
- }
- if (targetFbs != 1) {
- ALOGW("Saw %zu layers, posted=%d", num_layers, targetFbs);
- }
- Broadcast(buffer_idx);
- return 0;
-}
-
-uint8_t* VSoCComposer::RotateTmpBuffer(unsigned int order) {
- return &tmp_buffer_[(order % kNumTmpBufferPieces) * tmp_buffer_.size() /
- kNumTmpBufferPieces];
-}
-
-uint8_t* VSoCComposer::GetSpecialTmpBuffer(size_t needed_size) {
- special_tmp_buffer_.resize(needed_size);
- return &special_tmp_buffer_[0];
-}
-
-} // namespace cvd
diff --git a/guest/hals/hwcomposer/vsoc/vsoc_screen_view.cpp b/guest/hals/hwcomposer/vsoc/vsoc_screen_view.cpp
new file mode 100644
index 0000000..6ca9ac2
--- /dev/null
+++ b/guest/hals/hwcomposer/vsoc/vsoc_screen_view.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include "guest/hals/hwcomposer/vsoc/vsoc_screen_view.h"
+
+#include <sys/time.h>
+
+#include "common/vsoc/lib/screen_region_view.h"
+
+using vsoc::layout::screen::TimeSpec;
+using vsoc::screen::ScreenRegionView;
+
+namespace cvd {
+namespace {
+
+TimeSpec TimeSpecFromSystemStruct(const timespec* spec) {
+ return {static_cast<uint32_t>(spec->tv_sec),
+ static_cast<uint32_t>(spec->tv_nsec), 0};
+}
+
+void VSoCStatsFromCvdStats(vsoc::layout::screen::CompositionStats* vsoc_stats,
+ const cvd::CompositionStats* stats) {
+ vsoc_stats->num_prepare_calls = stats->num_prepare_calls;
+ vsoc_stats->num_layers = stats->num_layers;
+ vsoc_stats->num_hwcomposited_layers = stats->num_hwcomposited_layers;
+ vsoc_stats->last_vsync = TimeSpecFromSystemStruct(&stats->last_vsync);
+ vsoc_stats->prepare_start = TimeSpecFromSystemStruct(&stats->prepare_start);
+ vsoc_stats->prepare_end = TimeSpecFromSystemStruct(&stats->prepare_end);
+ vsoc_stats->set_start = TimeSpecFromSystemStruct(&stats->set_start);
+ vsoc_stats->set_end = TimeSpecFromSystemStruct(&stats->set_end);
+}
+
+} // namespace
+
+VSoCScreenView::VSoCScreenView()
+ : region_view_(ScreenRegionView::GetInstance()) {}
+
+VSoCScreenView::~VSoCScreenView() {}
+
+void VSoCScreenView::Broadcast(int buffer_id,
+ const cvd::CompositionStats* stats) {
+ if (stats) {
+ vsoc::layout::screen::CompositionStats vsoc_stats;
+ VSoCStatsFromCvdStats(&vsoc_stats, stats);
+ region_view_->BroadcastNewFrame(buffer_id, &vsoc_stats);
+ } else {
+ region_view_->BroadcastNewFrame(buffer_id);
+ }
+}
+
+void* VSoCScreenView::GetBuffer(int fb_index) {
+ return region_view_->GetBuffer(fb_index);
+}
+
+int32_t VSoCScreenView::x_res() const { return region_view_->x_res(); }
+
+int32_t VSoCScreenView::y_res() const { return region_view_->y_res(); }
+
+int32_t VSoCScreenView::dpi() const { return region_view_->dpi(); }
+
+int32_t VSoCScreenView::refresh_rate() const {
+ return region_view_->refresh_rate_hz();
+}
+
+int VSoCScreenView::num_buffers() const {
+ return region_view_->number_of_buffers();
+}
+} // namespace cvd
diff --git a/guest/hals/hwcomposer/vsoc/vsoc_screen_view.h b/guest/hals/hwcomposer/vsoc/vsoc_screen_view.h
new file mode 100644
index 0000000..1ecace6
--- /dev/null
+++ b/guest/hals/hwcomposer/vsoc/vsoc_screen_view.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+#pragma once
+
+#include <condition_variable>
+#include <functional>
+#include <mutex>
+#include <thread>
+#include <vector>
+
+#include "common/libs/fs/shared_fd.h"
+#include "common/vsoc/lib/screen_region_view.h"
+#include "guest/hals/hwcomposer/common/screen_view.h"
+
+namespace cvd {
+
+class VSoCScreenView : public ScreenView {
+ public:
+ VSoCScreenView();
+ virtual ~VSoCScreenView();
+
+ void Broadcast(int buffer_id,
+ const CompositionStats* stats = nullptr) override;
+ void* GetBuffer(int fb_index) override;
+
+ int32_t x_res() const override;
+ int32_t y_res() const override;
+ int32_t dpi() const override;
+ int32_t refresh_rate() const override;
+
+ int num_buffers() const override;
+
+ private:
+ vsoc::screen::ScreenRegionView* region_view_;
+};
+
+} // namespace cvd