Merge "ultrahdr: Update fuzz application for encode API" into udc-dev
diff --git a/libs/ultrahdr/include/ultrahdr/ultrahdr.h b/libs/ultrahdr/include/ultrahdr/ultrahdr.h
index d6153e9..21751b4 100644
--- a/libs/ultrahdr/include/ultrahdr/ultrahdr.h
+++ b/libs/ultrahdr/include/ultrahdr/ultrahdr.h
@@ -20,7 +20,7 @@
namespace android::ultrahdr {
// Color gamuts for image data
typedef enum {
- ULTRAHDR_COLORGAMUT_UNSPECIFIED,
+ ULTRAHDR_COLORGAMUT_UNSPECIFIED = -1,
ULTRAHDR_COLORGAMUT_BT709,
ULTRAHDR_COLORGAMUT_P3,
ULTRAHDR_COLORGAMUT_BT2100,
@@ -52,7 +52,7 @@
*/
struct ultrahdr_metadata_struct {
// Ultra HDR library version
- const char* version;
+ std::string version;
// Max Content Boost for the map
float maxContentBoost;
// Min Content Boost for the map
diff --git a/libs/ultrahdr/jpegencoderhelper.cpp b/libs/ultrahdr/jpegencoderhelper.cpp
index 10a7630..ab2f8c7 100644
--- a/libs/ultrahdr/jpegencoderhelper.cpp
+++ b/libs/ultrahdr/jpegencoderhelper.cpp
@@ -22,6 +22,8 @@
namespace android::ultrahdr {
+#define ALIGNM(x, m) ((((x) + ((m) - 1)) / (m)) * (m))
+
// The destination manager that can access |mResultBuffer| in JpegEncoderHelper.
struct destination_mgr {
public:
@@ -175,6 +177,37 @@
std::unique_ptr<uint8_t[]> empty(new uint8_t[cinfo->image_width]);
memset(empty.get(), 0, cinfo->image_width);
+ const int aligned_width = ALIGNM(cinfo->image_width, kCompressBatchSize);
+ const bool is_width_aligned = (aligned_width == cinfo->image_width);
+ std::unique_ptr<uint8_t[]> buffer_intrm = nullptr;
+ uint8_t* y_plane_intrm = nullptr;
+ uint8_t* u_plane_intrm = nullptr;
+ uint8_t* v_plane_intrm = nullptr;
+ JSAMPROW y_intrm[kCompressBatchSize];
+ JSAMPROW cb_intrm[kCompressBatchSize / 2];
+ JSAMPROW cr_intrm[kCompressBatchSize / 2];
+ JSAMPARRAY planes_intrm[3]{y_intrm, cb_intrm, cr_intrm};
+ if (!is_width_aligned) {
+ size_t mcu_row_size = aligned_width * kCompressBatchSize * 3 / 2;
+ buffer_intrm = std::make_unique<uint8_t[]>(mcu_row_size);
+ y_plane_intrm = buffer_intrm.get();
+ u_plane_intrm = y_plane_intrm + (aligned_width * kCompressBatchSize);
+ v_plane_intrm = u_plane_intrm + (aligned_width * kCompressBatchSize) / 4;
+ for (int i = 0; i < kCompressBatchSize; ++i) {
+ y_intrm[i] = y_plane_intrm + i * aligned_width;
+ memset(y_intrm[i] + cinfo->image_width, 0, aligned_width - cinfo->image_width);
+ }
+ for (int i = 0; i < kCompressBatchSize / 2; ++i) {
+ int offset_intrm = i * (aligned_width / 2);
+ cb_intrm[i] = u_plane_intrm + offset_intrm;
+ cr_intrm[i] = v_plane_intrm + offset_intrm;
+ memset(cb_intrm[i] + cinfo->image_width / 2, 0,
+ (aligned_width - cinfo->image_width) / 2);
+ memset(cr_intrm[i] + cinfo->image_width / 2, 0,
+ (aligned_width - cinfo->image_width) / 2);
+ }
+ }
+
while (cinfo->next_scanline < cinfo->image_height) {
for (int i = 0; i < kCompressBatchSize; ++i) {
size_t scanline = cinfo->next_scanline + i;
@@ -183,6 +216,9 @@
} else {
y[i] = empty.get();
}
+ if (!is_width_aligned) {
+ memcpy(y_intrm[i], y[i], cinfo->image_width);
+ }
}
// cb, cr only have half scanlines
for (int i = 0; i < kCompressBatchSize / 2; ++i) {
@@ -194,9 +230,13 @@
} else {
cb[i] = cr[i] = empty.get();
}
+ if (!is_width_aligned) {
+ memcpy(cb_intrm[i], cb[i], cinfo->image_width / 2);
+ memcpy(cr_intrm[i], cr[i], cinfo->image_width / 2);
+ }
}
-
- int processed = jpeg_write_raw_data(cinfo, planes, kCompressBatchSize);
+ int processed = jpeg_write_raw_data(cinfo, is_width_aligned ? planes : planes_intrm,
+ kCompressBatchSize);
if (processed != kCompressBatchSize) {
ALOGE("Number of processed lines does not equal input lines.");
return false;
@@ -213,6 +253,23 @@
std::unique_ptr<uint8_t[]> empty(new uint8_t[cinfo->image_width]);
memset(empty.get(), 0, cinfo->image_width);
+ const int aligned_width = ALIGNM(cinfo->image_width, kCompressBatchSize);
+ bool is_width_aligned = (aligned_width == cinfo->image_width);
+ std::unique_ptr<uint8_t[]> buffer_intrm = nullptr;
+ uint8_t* y_plane_intrm = nullptr;
+ uint8_t* u_plane_intrm = nullptr;
+ JSAMPROW y_intrm[kCompressBatchSize];
+ JSAMPARRAY planes_intrm[]{y_intrm};
+ if (!is_width_aligned) {
+ size_t mcu_row_size = aligned_width * kCompressBatchSize;
+ buffer_intrm = std::make_unique<uint8_t[]>(mcu_row_size);
+ y_plane_intrm = buffer_intrm.get();
+ for (int i = 0; i < kCompressBatchSize; ++i) {
+ y_intrm[i] = y_plane_intrm + i * aligned_width;
+ memset(y_intrm[i] + cinfo->image_width, 0, aligned_width - cinfo->image_width);
+ }
+ }
+
while (cinfo->next_scanline < cinfo->image_height) {
for (int i = 0; i < kCompressBatchSize; ++i) {
size_t scanline = cinfo->next_scanline + i;
@@ -221,8 +278,12 @@
} else {
y[i] = empty.get();
}
+ if (!is_width_aligned) {
+ memcpy(y_intrm[i], y[i], cinfo->image_width);
+ }
}
- int processed = jpeg_write_raw_data(cinfo, planes, kCompressBatchSize);
+ int processed = jpeg_write_raw_data(cinfo, is_width_aligned ? planes : planes_intrm,
+ kCompressBatchSize);
if (processed != kCompressBatchSize / 2) {
ALOGE("Number of processed lines does not equal input lines.");
return false;
diff --git a/libs/ultrahdr/jpegr.cpp b/libs/ultrahdr/jpegr.cpp
index c250aa0..b2bde6c 100644
--- a/libs/ultrahdr/jpegr.cpp
+++ b/libs/ultrahdr/jpegr.cpp
@@ -76,9 +76,9 @@
// JPEG encoding / decoding will require block based DCT transform 16 x 16 for luma,
// and 8 x 8 for chroma.
// Width must be 16 dividable for luma, and 8 dividable for chroma.
-// If this criteria is not ficilitated, we will pad zeros based on the required block size.
+// If this criteria is not facilitated, we will pad zeros based to each line on the
+// required block size.
static const size_t kJpegBlock = JpegEncoderHelper::kCompressBatchSize;
-static const size_t kJpegBlockSquare = kJpegBlock * kJpegBlock;
// JPEG compress quality (0 ~ 100) for gain map
static const int kMapCompressQuality = 85;
@@ -145,7 +145,8 @@
return ERROR_JPEGR_INVALID_NULL_PTR;
}
- if (hdr_tf <= ULTRAHDR_TF_UNSPECIFIED || hdr_tf > ULTRAHDR_TF_MAX) {
+ if (hdr_tf <= ULTRAHDR_TF_UNSPECIFIED || hdr_tf > ULTRAHDR_TF_MAX
+ || hdr_tf == ULTRAHDR_TF_SRGB) {
ALOGE("Invalid hdr transfer function %d", hdr_tf);
return ERROR_JPEGR_INVALID_INPUT_TYPE;
}
@@ -228,13 +229,8 @@
metadata.version = kJpegrVersion;
jpegr_uncompressed_struct uncompressed_yuv_420_image;
- size_t gain_map_length = uncompressed_p010_image->width * uncompressed_p010_image->height * 3 / 2;
- // Pad a pseudo chroma block (kJpegBlock / 2) x (kJpegBlock / 2)
- // if width is not kJpegBlock aligned.
- if (uncompressed_p010_image->width % kJpegBlock != 0) {
- gain_map_length += kJpegBlockSquare / 4;
- }
- unique_ptr<uint8_t[]> uncompressed_yuv_420_image_data = make_unique<uint8_t[]>(gain_map_length);
+ unique_ptr<uint8_t[]> uncompressed_yuv_420_image_data = make_unique<uint8_t[]>(
+ uncompressed_p010_image->width * uncompressed_p010_image->height * 3 / 2);
uncompressed_yuv_420_image.data = uncompressed_yuv_420_image_data.get();
JPEGR_CHECK(toneMap(uncompressed_p010_image, &uncompressed_yuv_420_image));
@@ -509,11 +505,6 @@
return ERROR_JPEGR_INVALID_INPUT_TYPE;
}
- if (gain_map != nullptr && gain_map->data == nullptr) {
- ALOGE("received nullptr address for gain map data");
- return ERROR_JPEGR_INVALID_INPUT_TYPE;
- }
-
if (output_format == ULTRAHDR_OUTPUT_SDR) {
JpegDecoderHelper jpeg_decoder;
if (!jpeg_decoder.decompressImage(compressed_jpegr_image->data, compressed_jpegr_image->length,
@@ -555,6 +546,11 @@
if (!gain_map_decoder.decompressImage(compressed_map.data, compressed_map.length)) {
return ERROR_JPEGR_DECODE_ERROR;
}
+ if ((gain_map_decoder.getDecompressedImageWidth() *
+ gain_map_decoder.getDecompressedImageHeight()) >
+ gain_map_decoder.getDecompressedImageSize()) {
+ return ERROR_JPEGR_CALCULATION_ERROR;
+ }
if (gain_map != nullptr) {
gain_map->width = gain_map_decoder.getDecompressedImageWidth();
@@ -584,6 +580,11 @@
if (!jpeg_decoder.decompressImage(compressed_jpegr_image->data, compressed_jpegr_image->length)) {
return ERROR_JPEGR_DECODE_ERROR;
}
+ if ((jpeg_decoder.getDecompressedImageWidth() *
+ jpeg_decoder.getDecompressedImageHeight() * 3 / 2) >
+ jpeg_decoder.getDecompressedImageSize()) {
+ return ERROR_JPEGR_CALCULATION_ERROR;
+ }
if (exif != nullptr) {
if (exif->data == nullptr) {
@@ -605,7 +606,6 @@
uncompressed_yuv_420_image.data = jpeg_decoder.getDecompressedImagePtr();
uncompressed_yuv_420_image.width = jpeg_decoder.getDecompressedImageWidth();
uncompressed_yuv_420_image.height = jpeg_decoder.getDecompressedImageHeight();
-
JPEGR_CHECK(applyGainMap(&uncompressed_yuv_420_image, &map, &uhdr_metadata, output_format,
max_display_boost, dest));
return NO_ERROR;
@@ -848,6 +848,20 @@
return ERROR_JPEGR_INVALID_NULL_PTR;
}
+ // TODO: remove once map scaling factor is computed based on actual map dims
+ size_t image_width = uncompressed_yuv_420_image->width;
+ size_t image_height = uncompressed_yuv_420_image->height;
+ size_t map_width = image_width / kMapDimensionScaleFactor;
+ size_t map_height = image_height / kMapDimensionScaleFactor;
+ map_width = static_cast<size_t>(
+ floor((map_width + kJpegBlock - 1) / kJpegBlock)) * kJpegBlock;
+ map_height = ((map_height + 1) >> 1) << 1;
+ if (map_width != uncompressed_gain_map->width
+ || map_height != uncompressed_gain_map->height) {
+ ALOGE("gain map dimensions and primary image dimensions are not to scale");
+ return ERROR_JPEGR_INVALID_INPUT_TYPE;
+ }
+
dest->width = uncompressed_yuv_420_image->width;
dest->height = uncompressed_yuv_420_image->height;
ShepardsIDW idwTable(kMapDimensionScaleFactor);
diff --git a/libs/ultrahdr/tests/jpegencoderhelper_test.cpp b/libs/ultrahdr/tests/jpegencoderhelper_test.cpp
index 8f18ac0..f0e1fa4 100644
--- a/libs/ultrahdr/tests/jpegencoderhelper_test.cpp
+++ b/libs/ultrahdr/tests/jpegencoderhelper_test.cpp
@@ -108,18 +108,9 @@
ASSERT_GT(encoder.getCompressedImageSize(), static_cast<uint32_t>(0));
}
-// The width of the "unaligned" image is not 16-aligned, and will fail if encoded directly.
-// Should pass with the padding zero method.
TEST_F(JpegEncoderHelperTest, encodeUnalignedImage) {
JpegEncoderHelper encoder;
- const size_t paddingZeroLength = JpegEncoderHelper::kCompressBatchSize
- * JpegEncoderHelper::kCompressBatchSize / 4;
- std::unique_ptr<uint8_t[]> imageWithPaddingZeros(
- new uint8_t[UNALIGNED_IMAGE_WIDTH * UNALIGNED_IMAGE_HEIGHT * 3 / 2
- + paddingZeroLength]);
- memcpy(imageWithPaddingZeros.get(), mUnalignedImage.buffer.get(),
- UNALIGNED_IMAGE_WIDTH * UNALIGNED_IMAGE_HEIGHT * 3 / 2);
- EXPECT_TRUE(encoder.compressImage(imageWithPaddingZeros.get(), mUnalignedImage.width,
+ EXPECT_TRUE(encoder.compressImage(mUnalignedImage.buffer.get(), mUnalignedImage.width,
mUnalignedImage.height, JPEG_QUALITY, NULL, 0));
ASSERT_GT(encoder.getCompressedImageSize(), static_cast<uint32_t>(0));
}
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 0cc7cfb..fbbb388 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -6700,6 +6700,13 @@
for (const auto& [displayId, handles] : handlesPerDisplay) {
setInputWindowsLocked(handles, displayId);
}
+
+ if (update.vsyncId < mWindowInfosVsyncId) {
+ ALOGE("Received out of order window infos update. Last update vsync id: %" PRId64
+ ", current update vsync id: %" PRId64,
+ mWindowInfosVsyncId, update.vsyncId);
+ }
+ mWindowInfosVsyncId = update.vsyncId;
}
// Wake up poll loop since it may need to make new input dispatching choices.
mLooper->wake();
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 8ca01b7..6b22f2f 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -204,6 +204,8 @@
const IdGenerator mIdGenerator;
+ int64_t mWindowInfosVsyncId GUARDED_BY(mLock);
+
// With each iteration, InputDispatcher nominally processes one queued event,
// a timeout, or a response from an input consumer.
// This method should only be called on the input dispatcher's own thread.
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
index 37b68c8..f8b466c 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
@@ -223,7 +223,7 @@
}
void PowerAdvisor::reportActualWorkDuration() {
- if (!mBootFinished || !usePowerHintSession()) {
+ if (!mBootFinished || !sUseReportActualDuration || !usePowerHintSession()) {
ALOGV("Actual work duration power hint cannot be sent, skipping");
return;
}
@@ -564,6 +564,9 @@
base::GetIntProperty<int64_t>("debug.sf.hint_margin_us",
ticks<std::micro>(PowerAdvisor::kDefaultTargetSafetyMargin)));
+const bool PowerAdvisor::sUseReportActualDuration =
+ base::GetBoolProperty(std::string("debug.adpf.use_report_actual_duration"), true);
+
power::PowerHalController& PowerAdvisor::getPowerHal() {
static std::once_flag halFlag;
std::call_once(halFlag, [this] { mPowerHal->init(); });
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
index 7a0d426..f0d3fd8 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
@@ -269,6 +269,9 @@
static const Duration sTargetSafetyMargin;
static constexpr const Duration kDefaultTargetSafetyMargin{1ms};
+ // Whether we should send reportActualWorkDuration calls
+ static const bool sUseReportActualDuration;
+
// How long we expect hwc to run after the present call until it waits for the fence
static constexpr const Duration kFenceWaitStartDelayValidated{150us};
static constexpr const Duration kFenceWaitStartDelaySkippedValidate{250us};
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 2ac1db9..79378be 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2485,7 +2485,10 @@
mPowerAdvisor->setFrameDelay(frameDelay);
mPowerAdvisor->setTotalFrameTargetWorkDuration(idealSfWorkDuration);
- mPowerAdvisor->updateTargetWorkDuration(vsyncPeriod);
+
+ const auto& display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked()).get();
+ const Period idealVsyncPeriod = display->getActiveMode().fps.getPeriod();
+ mPowerAdvisor->updateTargetWorkDuration(idealVsyncPeriod);
}
if (mRefreshRateOverlaySpinner) {