| /* |
| * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are |
| * met: |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * Redistributions in binary form must reproduce the above |
| * copyright notice, this list of conditions and the following |
| * disclaimer in the documentation and/or other materials provided |
| * with the distribution. |
| * * Neither the name of The Linux Foundation nor the names of its |
| * contributors may be used to endorse or promote products derived |
| * from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS |
| * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
| * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
| * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE |
| * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN |
| * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include <cutils/properties.h> |
| #include <sys/mman.h> |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <utils/constants.h> |
| #include <utils/debug.h> |
| #include <utils/formats.h> |
| #include <algorithm> |
| #include <array> |
| #include <sstream> |
| #include <string> |
| #include <fstream> |
| |
| #include "hwc_display_pluggable_test.h" |
| #include "hwc_debugger.h" |
| |
| #define __CLASS__ "HWCDisplayPluggableTest" |
| |
| namespace sdm { |
| |
| using std::array; |
| |
| int HWCDisplayPluggableTest::Create(CoreInterface *core_intf, HWCBufferAllocator *buffer_allocator, |
| HWCCallbacks *callbacks, HWCDisplayEventHandler *event_handler, |
| qService::QService *qservice, hwc2_display_t id, |
| int32_t sdm_id, uint32_t panel_bpp, uint32_t pattern_type, |
| HWCDisplay **hwc_display) { |
| HWCDisplay *hwc_pluggable_test = new HWCDisplayPluggableTest(core_intf, buffer_allocator, |
| callbacks, event_handler, qservice, |
| id, sdm_id, panel_bpp, pattern_type); |
| |
| int status = hwc_pluggable_test->Init(); |
| if (status) { |
| delete hwc_pluggable_test; |
| return status; |
| } |
| |
| *hwc_display = hwc_pluggable_test; |
| |
| DLOGD("Pluggable panel_bpp %d, pattern_type %d", panel_bpp, pattern_type); |
| |
| return status; |
| } |
| |
| void HWCDisplayPluggableTest::Destroy(HWCDisplay *hwc_display) { |
| // Flush the display to have outstanding fences signaled. |
| hwc_display->Flush(); |
| hwc_display->Deinit(); |
| |
| delete hwc_display; |
| } |
| |
| HWCDisplayPluggableTest::HWCDisplayPluggableTest(CoreInterface *core_intf, |
| HWCBufferAllocator *buffer_allocator, |
| HWCCallbacks *callbacks, |
| HWCDisplayEventHandler *event_handler, |
| qService::QService *qservice, hwc2_display_t id, |
| int32_t sdm_id, uint32_t panel_bpp, |
| uint32_t pattern_type) |
| : HWCDisplay(core_intf, buffer_allocator, callbacks, event_handler, qservice, kPluggable, id, |
| sdm_id, DISPLAY_CLASS_PLUGGABLE), |
| panel_bpp_(panel_bpp), pattern_type_(pattern_type) { |
| } |
| |
| int HWCDisplayPluggableTest::Init() { |
| uint32_t pluggable_width = 0; |
| uint32_t pluggable_height = 0; |
| |
| int status = HWCDisplay::Init(); |
| if (status) { |
| DLOGE("HWCDisplayPluggableTest::Init status = %d ", status); |
| return status; |
| } |
| |
| status = CreateLayerStack(); |
| if (status) { |
| Deinit(); |
| return status; |
| } |
| |
| DisplayError error = HWCDisplay::GetMixerResolution(&pluggable_width, &pluggable_height); |
| if (error != kErrorNone) { |
| Deinit(); |
| return -EINVAL; |
| } |
| |
| status = HWCDisplay::SetFrameBufferResolution(pluggable_width, pluggable_height); |
| if (status) { |
| Deinit(); |
| DLOGE("HWCDisplayPluggableTest:: set fb resolution status = %d ", status); |
| return status; |
| } |
| |
| return status; |
| } |
| |
| int HWCDisplayPluggableTest::Deinit() { |
| DestroyLayerStack(); |
| return HWCDisplay::Deinit(); |
| } |
| |
| |
| HWC2::Error HWCDisplayPluggableTest::Validate(uint32_t *out_num_types, uint32_t *out_num_requests) { |
| auto status = HWC2::Error::None; |
| if (active_secure_sessions_[kSecureDisplay] || display_paused_) { |
| MarkLayersForGPUBypass(); |
| return status; |
| } |
| |
| if (layer_set_.empty()) { |
| flush_ = true; |
| return status; |
| } |
| |
| if (shutdown_pending_) { |
| return status; |
| } |
| DisplayError error = display_intf_->Prepare(&layer_stack_); |
| if (error != kErrorNone) { |
| if (error == kErrorShutDown) { |
| shutdown_pending_ = true; |
| } else if (error != kErrorPermission) { |
| DLOGE("Prepare failed. Error = %d", error); |
| // To prevent surfaceflinger infinite wait, flush the previous frame during Commit() |
| // so that previous buffer and fences are released, and override the error. |
| flush_ = true; |
| } |
| } |
| |
| MarkLayersForGPUBypass(); |
| |
| return status; |
| } |
| |
| HWC2::Error HWCDisplayPluggableTest::Present(shared_ptr<Fence> *out_retire_fence) { |
| auto status = HWC2::Error::None; |
| |
| if (active_secure_sessions_[kSecureDisplay]) { |
| return status; |
| } |
| |
| if (display_paused_) { |
| DisplayError error = display_intf_->Flush(&layer_stack_); |
| if (error != kErrorNone) { |
| DLOGE("Flush failed. Error = %d", error); |
| } |
| } |
| |
| if (shutdown_pending_) { |
| return status; |
| } |
| |
| DumpInputBuffer(); |
| |
| if (!flush_) { |
| DisplayError error = kErrorUndefined; |
| error = display_intf_->Commit(&layer_stack_); |
| if (error == kErrorNone) { |
| // A commit is successfully submitted, start flushing on failure now onwards. |
| flush_on_error_ = true; |
| } else if (error == kErrorShutDown) { |
| shutdown_pending_ = true; |
| status = HWC2::Error::Unsupported; |
| } else if (error == kErrorNotValidated) { |
| status = HWC2::Error::NotValidated; |
| } else if (error != kErrorPermission) { |
| DLOGE("Commit failed. Error = %d", error); |
| // To prevent surfaceflinger infinite wait, flush the previous frame during Commit() |
| // so that previous buffer and fences are released, and override the error. |
| flush_ = true; |
| } |
| } |
| PostCommit(out_retire_fence); |
| return status; |
| } |
| |
| int HWCDisplayPluggableTest::Perform(uint32_t operation, ...) { |
| return 0; |
| } |
| |
| void HWCDisplayPluggableTest::DumpInputBuffer() { |
| if (!dump_frame_count_ || flush_ || !dump_input_layers_) { |
| return; |
| } |
| |
| const char *dir_path = "/data/vendor/display/frame_dump_external"; |
| uint32_t width = buffer_info_.alloc_buffer_info.aligned_width; |
| uint32_t height = buffer_info_.alloc_buffer_info.aligned_height; |
| string format_str = GetFormatString(buffer_info_.buffer_config.format); |
| |
| char *buffer = reinterpret_cast<char *>(mmap(NULL, buffer_info_.alloc_buffer_info.size, |
| PROT_READ|PROT_WRITE, MAP_SHARED, |
| buffer_info_.alloc_buffer_info.fd, 0)); |
| if (buffer == MAP_FAILED) { |
| DLOGW("mmap failed. err = %d", errno); |
| return; |
| } |
| |
| if (mkdir(dir_path, 0777) != 0 && errno != EEXIST) { |
| DLOGW("Failed to create %s directory errno = %d, desc = %s", dir_path, errno, strerror(errno)); |
| return; |
| } |
| |
| // if directory exists already, need to explicitly change the permission. |
| if (errno == EEXIST && chmod(dir_path, 0777) != 0) { |
| DLOGW("Failed to change permissions on %s directory", dir_path); |
| return; |
| } |
| |
| if (buffer) { |
| std::stringstream dump_file_name; |
| dump_file_name << dir_path; |
| dump_file_name << "/input_layer_" << width << "x" << height << "_" << format_str << ".raw"; |
| |
| std::fstream fs; |
| fs.open(dump_file_name.str().c_str(), std::fstream::in | std::fstream::out | std::fstream::app); |
| if (!fs.is_open()) { |
| DLOGI("File open failed %s", dump_file_name.str().c_str()); |
| return; |
| } |
| |
| fs.write(buffer, (std::streamsize)buffer_info_.alloc_buffer_info.size); |
| fs.close(); |
| |
| DLOGI("Frame Dump %s: is successful", dump_file_name.str().c_str()); |
| } |
| |
| // Dump only once as the content is going to be same for all draw cycles |
| if (dump_frame_count_) { |
| dump_frame_count_ = 0; |
| } |
| |
| if (munmap(buffer, buffer_info_.alloc_buffer_info.size) != 0) { |
| DLOGW("munmap failed. err = %d", errno); |
| return; |
| } |
| } |
| |
| void HWCDisplayPluggableTest::CalcCRC(uint32_t color_val, std::bitset<16> *crc_data) { |
| std::bitset<16> color = {}; |
| std::bitset<16> temp_crc = {}; |
| |
| switch (panel_bpp_) { |
| case kDisplayBpp18: |
| color = (color_val & 0xFC) << 8; |
| break; |
| case kDisplayBpp24: |
| color = color_val << 8; |
| break; |
| case kDisplayBpp30: |
| color = color_val << 6; |
| break; |
| default: |
| return; |
| } |
| |
| temp_crc[15] = (*crc_data)[0] ^ (*crc_data)[1] ^ (*crc_data)[2] ^ (*crc_data)[3] ^ |
| (*crc_data)[4] ^ (*crc_data)[5] ^ (*crc_data)[6] ^ (*crc_data)[7] ^ |
| (*crc_data)[8] ^ (*crc_data)[9] ^ (*crc_data)[10] ^ (*crc_data)[11] ^ |
| (*crc_data)[12] ^ (*crc_data)[14] ^ (*crc_data)[15] ^ color[0] ^ color[1] ^ |
| color[2] ^ color[3] ^ color[4] ^ color[5] ^ color[6] ^ color[7] ^ color[8] ^ |
| color[9] ^ color[10] ^ color[11] ^ color[12] ^ color[14] ^ color[15]; |
| |
| temp_crc[14] = (*crc_data)[12] ^ (*crc_data)[13] ^ color[12] ^ color[13]; |
| temp_crc[13] = (*crc_data)[11] ^ (*crc_data)[12] ^ color[11] ^ color[12]; |
| temp_crc[12] = (*crc_data)[10] ^ (*crc_data)[11] ^ color[10] ^ color[11]; |
| temp_crc[11] = (*crc_data)[9] ^ (*crc_data)[10] ^ color[9] ^ color[10]; |
| temp_crc[10] = (*crc_data)[8] ^ (*crc_data)[9] ^ color[8] ^ color[9]; |
| temp_crc[9] = (*crc_data)[7] ^ (*crc_data)[8] ^ color[7] ^ color[8]; |
| temp_crc[8] = (*crc_data)[6] ^ (*crc_data)[7] ^ color[6] ^ color[7]; |
| temp_crc[7] = (*crc_data)[5] ^ (*crc_data)[6] ^ color[5] ^ color[6]; |
| temp_crc[6] = (*crc_data)[4] ^ (*crc_data)[5] ^ color[4] ^ color[5]; |
| temp_crc[5] = (*crc_data)[3] ^ (*crc_data)[4] ^ color[3] ^ color[4]; |
| temp_crc[4] = (*crc_data)[2] ^ (*crc_data)[3] ^ color[2] ^ color[3]; |
| temp_crc[3] = (*crc_data)[1] ^ (*crc_data)[2] ^ (*crc_data)[15] ^ color[1] ^ color[2] ^ color[15]; |
| temp_crc[2] = (*crc_data)[0] ^ (*crc_data)[1] ^ (*crc_data)[14] ^ color[0] ^ color[1] ^ color[14]; |
| |
| temp_crc[1] = (*crc_data)[1] ^ (*crc_data)[2] ^ (*crc_data)[3] ^ (*crc_data)[4] ^ (*crc_data)[5] ^ |
| (*crc_data)[6] ^ (*crc_data)[7] ^ (*crc_data)[8] ^ (*crc_data)[9] ^ |
| (*crc_data)[10] ^ (*crc_data)[11] ^ (*crc_data)[12] ^ (*crc_data)[13] ^ |
| (*crc_data)[14] ^ color[1] ^ color[2] ^ color[3] ^ color[4] ^ color[5] ^ color[6] ^ |
| color[7] ^ color[8] ^ color[9] ^ color[10] ^ color[11] ^ color[12] ^ color[13] ^ |
| color[14]; |
| |
| temp_crc[0] = (*crc_data)[0] ^ (*crc_data)[1] ^ (*crc_data)[2] ^ (*crc_data)[3] ^ (*crc_data)[4] ^ |
| (*crc_data)[5] ^ (*crc_data)[6] ^ (*crc_data)[7] ^ (*crc_data)[8] ^ (*crc_data)[9] ^ |
| (*crc_data)[10] ^ (*crc_data)[11] ^ (*crc_data)[12] ^ (*crc_data)[13] ^ |
| (*crc_data)[15] ^ color[0] ^ color[1] ^ color[2] ^ color[3] ^ color[4] ^ color[5] ^ |
| color[6] ^ color[7] ^ color[8] ^ color[9] ^ color[10] ^ color[11] ^ color[12] ^ |
| color[13] ^ color[15]; |
| |
| (*crc_data) = temp_crc; |
| } |
| |
| int HWCDisplayPluggableTest::FillBuffer() { |
| uint8_t *buffer = reinterpret_cast<uint8_t *>(mmap(NULL, buffer_info_.alloc_buffer_info.size, |
| PROT_READ|PROT_WRITE, MAP_SHARED, |
| buffer_info_.alloc_buffer_info.fd, 0)); |
| if (buffer == MAP_FAILED) { |
| DLOGE("mmap failed. err = %d", errno); |
| return -EFAULT; |
| } |
| |
| switch (pattern_type_) { |
| case kPatternColorRamp: |
| GenerateColorRamp(buffer); |
| break; |
| case kPatternBWVertical: |
| GenerateBWVertical(buffer); |
| break; |
| case kPatternColorSquare: |
| GenerateColorSquare(buffer); |
| break; |
| default: |
| DLOGW("Invalid Pattern type %d", pattern_type_); |
| return -EINVAL; |
| } |
| |
| if (munmap(buffer, buffer_info_.alloc_buffer_info.size) != 0) { |
| DLOGE("munmap failed. err = %d", errno); |
| return -EFAULT; |
| } |
| |
| return 0; |
| } |
| |
| int HWCDisplayPluggableTest::GetStride(LayerBufferFormat format, uint32_t width, uint32_t *stride) { |
| switch (format) { |
| case kFormatRGBA8888: |
| case kFormatRGBA1010102: |
| *stride = width * 4; |
| break; |
| case kFormatRGB888: |
| *stride = width * 3; |
| break; |
| default: |
| DLOGW("Unsupported format type %d", format); |
| return -EINVAL; |
| } |
| |
| return 0; |
| } |
| |
| void HWCDisplayPluggableTest::PixelCopy(uint32_t red, uint32_t green, uint32_t blue, uint32_t alpha, |
| uint8_t **buffer) { |
| LayerBufferFormat format = buffer_info_.buffer_config.format; |
| |
| switch (format) { |
| case kFormatRGBA8888: |
| *(*buffer)++ = UINT8(red & 0xFF); |
| *(*buffer)++ = UINT8(green & 0xFF); |
| *(*buffer)++ = UINT8(blue & 0xFF); |
| *(*buffer)++ = UINT8(alpha & 0xFF); |
| break; |
| case kFormatRGB888: |
| *(*buffer)++ = UINT8(red & 0xFF); |
| *(*buffer)++ = UINT8(green & 0xFF); |
| *(*buffer)++ = UINT8(blue & 0xFF); |
| break; |
| case kFormatRGBA1010102: |
| // Lower 8 bits of red |
| *(*buffer)++ = UINT8(red & 0xFF); |
| |
| // Upper 2 bits of Red + Lower 6 bits of green |
| *(*buffer)++ = UINT8(((green & 0x3F) << 2) | ((red >> 0x8) & 0x3)); |
| |
| // Upper 4 bits of green + Lower 4 bits of blue |
| *(*buffer)++ = UINT8(((blue & 0xF) << 4) | ((green >> 6) & 0xF)); |
| |
| // Upper 6 bits of blue + Lower 2 bits of alpha |
| *(*buffer)++ = UINT8(((alpha & 0x3) << 6) | ((blue >> 4) & 0x3F)); |
| break; |
| default: |
| DLOGW("format not supported format = %d", format); |
| break; |
| } |
| } |
| |
| void HWCDisplayPluggableTest::GenerateColorRamp(uint8_t *buffer) { |
| uint32_t width = buffer_info_.buffer_config.width; |
| uint32_t height = buffer_info_.buffer_config.height; |
| LayerBufferFormat format = buffer_info_.buffer_config.format; |
| uint32_t aligned_width = buffer_info_.alloc_buffer_info.aligned_width; |
| uint32_t buffer_stride = 0; |
| |
| uint32_t color_ramp = 0; |
| uint32_t start_color_val = 0; |
| uint32_t step_size = 1; |
| uint32_t ramp_width = 0; |
| uint32_t ramp_height = 0; |
| uint32_t shift_by = 0; |
| |
| std::bitset<16> crc_red = {}; |
| std::bitset<16> crc_green = {}; |
| std::bitset<16> crc_blue = {}; |
| |
| switch (panel_bpp_) { |
| case kDisplayBpp18: |
| ramp_height = 64; |
| ramp_width = 64; |
| shift_by = 2; |
| break; |
| case kDisplayBpp24: |
| ramp_height = 64; |
| ramp_width = 256; |
| break; |
| case kDisplayBpp30: |
| ramp_height = 32; |
| ramp_width = 256; |
| start_color_val = 0x180; |
| break; |
| default: |
| return; |
| } |
| |
| GetStride(format, aligned_width, &buffer_stride); |
| |
| for (uint32_t loop_height = 0; loop_height < height; loop_height++) { |
| uint32_t color_value = start_color_val; |
| uint8_t *temp = buffer + (loop_height * buffer_stride); |
| |
| for (uint32_t loop_width = 0; loop_width < width; loop_width++) { |
| if (color_ramp == kColorRedRamp) { |
| PixelCopy(color_value, 0, 0, 0, &temp); |
| CalcCRC(color_value, &crc_red); |
| CalcCRC(0, &crc_green); |
| CalcCRC(0, &crc_blue); |
| } |
| if (color_ramp == kColorGreenRamp) { |
| PixelCopy(0, color_value, 0, 0, &temp); |
| CalcCRC(0, &crc_red); |
| CalcCRC(color_value, &crc_green); |
| CalcCRC(0, &crc_blue); |
| } |
| if (color_ramp == kColorBlueRamp) { |
| PixelCopy(0, 0, color_value, 0, &temp); |
| CalcCRC(0, &crc_red); |
| CalcCRC(0, &crc_green); |
| CalcCRC(color_value, &crc_blue); |
| } |
| if (color_ramp == kColorWhiteRamp) { |
| PixelCopy(color_value, color_value, color_value, 0, &temp); |
| CalcCRC(color_value, &crc_red); |
| CalcCRC(color_value, &crc_green); |
| CalcCRC(color_value, &crc_blue); |
| } |
| |
| color_value = (start_color_val + (((loop_width + 1) % ramp_width) * step_size)) << shift_by; |
| } |
| |
| if (panel_bpp_ == kDisplayBpp30 && ((loop_height + 1) % ramp_height) == 0) { |
| if (start_color_val == 0x180) { |
| start_color_val = 0; |
| step_size = 4; |
| } else { |
| start_color_val = 0x180; |
| step_size = 1; |
| color_ramp = (color_ramp + 1) % 4; |
| } |
| continue; |
| } |
| |
| if (((loop_height + 1) % ramp_height) == 0) { |
| color_ramp = (color_ramp + 1) % 4; |
| } |
| } |
| |
| DLOGI("CRC red %lx", crc_red.to_ulong()); |
| DLOGI("CRC green %lx", crc_green.to_ulong()); |
| DLOGI("CRC blue %lx", crc_blue.to_ulong()); |
| } |
| |
| void HWCDisplayPluggableTest::GenerateBWVertical(uint8_t *buffer) { |
| uint32_t width = buffer_info_.buffer_config.width; |
| uint32_t height = buffer_info_.buffer_config.height; |
| LayerBufferFormat format = buffer_info_.buffer_config.format; |
| uint32_t aligned_width = buffer_info_.alloc_buffer_info.aligned_width; |
| uint32_t buffer_stride = 0; |
| uint32_t bits_per_component = panel_bpp_ / 3; |
| uint32_t max_color_val = (1 << bits_per_component) - 1; |
| |
| std::bitset<16> crc_red = {}; |
| std::bitset<16> crc_green = {}; |
| std::bitset<16> crc_blue = {}; |
| |
| if (panel_bpp_ == kDisplayBpp18) { |
| max_color_val <<= 2; |
| } |
| |
| GetStride(format, aligned_width, &buffer_stride); |
| |
| for (uint32_t loop_height = 0; loop_height < height; loop_height++) { |
| uint32_t color = 0; |
| uint8_t *temp = buffer + (loop_height * buffer_stride); |
| |
| for (uint32_t loop_width = 0; loop_width < width; loop_width++) { |
| if (color == kColorBlack) { |
| PixelCopy(0, 0, 0, 0, &temp); |
| CalcCRC(0, &crc_red); |
| CalcCRC(0, &crc_green); |
| CalcCRC(0, &crc_blue); |
| } |
| if (color == kColorWhite) { |
| PixelCopy(max_color_val, max_color_val, max_color_val, 0, &temp); |
| CalcCRC(max_color_val, &crc_red); |
| CalcCRC(max_color_val, &crc_green); |
| CalcCRC(max_color_val, &crc_blue); |
| } |
| |
| color = (color + 1) % 2; |
| } |
| } |
| |
| DLOGI("CRC red %lx", crc_red.to_ulong()); |
| DLOGI("CRC green %lx", crc_green.to_ulong()); |
| DLOGI("CRC blue %lx", crc_blue.to_ulong()); |
| } |
| |
| void HWCDisplayPluggableTest::GenerateColorSquare(uint8_t *buffer) { |
| uint32_t width = buffer_info_.buffer_config.width; |
| uint32_t height = buffer_info_.buffer_config.height; |
| LayerBufferFormat format = buffer_info_.buffer_config.format; |
| uint32_t aligned_width = buffer_info_.alloc_buffer_info.aligned_width; |
| uint32_t buffer_stride = 0; |
| uint32_t max_color_val = 0; |
| uint32_t min_color_val = 0; |
| |
| std::bitset<16> crc_red = {}; |
| std::bitset<16> crc_green = {}; |
| std::bitset<16> crc_blue = {}; |
| |
| switch (panel_bpp_) { |
| case kDisplayBpp18: |
| max_color_val = 63 << 2; // CEA Dynamic range for 18bpp 0 - 63 |
| min_color_val = 0; |
| break; |
| case kDisplayBpp24: |
| max_color_val = 235; // CEA Dynamic range for 24bpp 16 - 235 |
| min_color_val = 16; |
| break; |
| case kDisplayBpp30: |
| max_color_val = 940; // CEA Dynamic range for 30bpp 64 - 940 |
| min_color_val = 64; |
| break; |
| default: |
| return; |
| } |
| |
| array<array<uint32_t, 3>, 8> colors = {{ |
| {{max_color_val, max_color_val, max_color_val}}, // White Color |
| {{max_color_val, max_color_val, min_color_val}}, // Yellow Color |
| {{min_color_val, max_color_val, max_color_val}}, // Cyan Color |
| {{min_color_val, max_color_val, min_color_val}}, // Green Color |
| {{max_color_val, min_color_val, max_color_val}}, // Megenta Color |
| {{max_color_val, min_color_val, min_color_val}}, // Red Color |
| {{min_color_val, min_color_val, max_color_val}}, // Blue Color |
| {{min_color_val, min_color_val, min_color_val}}, // Black Color |
| }}; |
| |
| GetStride(format, aligned_width, &buffer_stride); |
| |
| for (uint32_t loop_height = 0; loop_height < height; loop_height++) { |
| uint32_t color = 0; |
| uint8_t *temp = buffer + (loop_height * buffer_stride); |
| |
| for (uint32_t loop_width = 0; loop_width < width; loop_width++) { |
| PixelCopy(colors[color][0], colors[color][1], colors[color][2], 0, &temp); |
| CalcCRC(colors[color][0], &crc_red); |
| CalcCRC(colors[color][1], &crc_green); |
| CalcCRC(colors[color][2], &crc_blue); |
| |
| if (((loop_width + 1) % 64) == 0) { |
| color = (color + 1) % colors.size(); |
| } |
| } |
| |
| if (((loop_height + 1) % 64) == 0) { |
| std::reverse(colors.begin(), (colors.end() - 1)); |
| } |
| } |
| |
| DLOGI("CRC red %lx", crc_red.to_ulong()); |
| DLOGI("CRC green %lx", crc_green.to_ulong()); |
| DLOGI("CRC blue %lx", crc_blue.to_ulong()); |
| } |
| |
| int HWCDisplayPluggableTest::InitLayer(Layer *layer) { |
| uint32_t active_config = 0; |
| DisplayConfigVariableInfo var_info = {}; |
| |
| GetActiveDisplayConfig(&active_config); |
| |
| GetDisplayAttributesForConfig(INT32(active_config), &var_info); |
| |
| layer->flags.updating = 1; |
| layer->src_rect = LayerRect(0, 0, var_info.x_pixels, var_info.y_pixels); |
| layer->dst_rect = layer->src_rect; |
| layer->frame_rate = var_info.fps; |
| layer->blending = kBlendingPremultiplied; |
| |
| layer->input_buffer.unaligned_width = var_info.x_pixels; |
| layer->input_buffer.unaligned_height = var_info.y_pixels; |
| buffer_info_.buffer_config.format = kFormatRGBA8888; |
| |
| if (layer->composition != kCompositionGPUTarget) { |
| buffer_info_.buffer_config.width = var_info.x_pixels; |
| buffer_info_.buffer_config.height = var_info.y_pixels; |
| switch (panel_bpp_) { |
| case kDisplayBpp18: |
| case kDisplayBpp24: |
| buffer_info_.buffer_config.format = kFormatRGB888; |
| break; |
| case kDisplayBpp30: |
| buffer_info_.buffer_config.format = kFormatRGBA1010102; |
| break; |
| default: |
| DLOGW("panel bpp not supported %d", panel_bpp_); |
| return -EINVAL; |
| } |
| buffer_info_.buffer_config.buffer_count = 1; |
| |
| int ret = buffer_allocator_->AllocateBuffer(&buffer_info_); |
| if (ret != 0) { |
| DLOGE("Buffer allocation failed. ret: %d", ret); |
| return -ENOMEM; |
| } |
| |
| ret = FillBuffer(); |
| if (ret != 0) { |
| buffer_allocator_->FreeBuffer(&buffer_info_); |
| return ret; |
| } |
| |
| layer->input_buffer.width = buffer_info_.alloc_buffer_info.aligned_width; |
| layer->input_buffer.height = buffer_info_.alloc_buffer_info.aligned_height; |
| layer->input_buffer.size = buffer_info_.alloc_buffer_info.size; |
| layer->input_buffer.planes[0].fd = buffer_info_.alloc_buffer_info.fd; |
| layer->input_buffer.planes[0].stride = buffer_info_.alloc_buffer_info.stride; |
| layer->input_buffer.format = buffer_info_.buffer_config.format; |
| |
| DLOGI("Input buffer WxH %dx%d format %s size %d fd %d stride %d", layer->input_buffer.width, |
| layer->input_buffer.height, GetFormatString(layer->input_buffer.format), |
| layer->input_buffer.size, layer->input_buffer.planes[0].fd, |
| layer->input_buffer.planes[0].stride); |
| } |
| |
| return 0; |
| } |
| |
| int HWCDisplayPluggableTest::DeinitLayer(Layer *layer) { |
| if (layer->composition != kCompositionGPUTarget) { |
| int ret = buffer_allocator_->FreeBuffer(&buffer_info_); |
| if (ret != 0) { |
| DLOGE("Buffer deallocation failed. ret: %d", ret); |
| return -ENOMEM; |
| } |
| } |
| |
| return 0; |
| } |
| |
| int HWCDisplayPluggableTest::CreateLayerStack() { |
| for (uint32_t i = 0; i < (kTestLayerCnt + 1 /* one dummy gpu_target layer */); i++) { |
| Layer *layer = new Layer(); |
| |
| if (i == kTestLayerCnt) { |
| layer->composition = kCompositionGPUTarget; |
| } |
| DLOGD("External :: CreateLayerStack %d", i); |
| int ret = InitLayer(layer); |
| if (ret != 0) { |
| delete layer; |
| return ret; |
| } |
| layer_stack_.layers.push_back(layer); |
| } |
| |
| return 0; |
| } |
| |
| int HWCDisplayPluggableTest::DestroyLayerStack() { |
| for (uint32_t i = 0; i < UINT32(layer_stack_.layers.size()); i++) { |
| Layer *layer = layer_stack_.layers.at(i); |
| int ret = DeinitLayer(layer); |
| if (ret != 0) { |
| return ret; |
| } |
| delete layer; |
| } |
| layer_stack_.layers = {}; |
| |
| return 0; |
| } |
| |
| HWC2::Error HWCDisplayPluggableTest::PostCommit(shared_ptr<Fence> *out_retire_fence) { |
| auto status = HWC2::Error::None; |
| // Do no call flush on errors, if a successful buffer is never submitted. |
| if (flush_ && flush_on_error_) { |
| display_intf_->Flush(&layer_stack_); |
| } |
| flush_ = false; |
| |
| return status; |
| } |
| |
| } // namespace sdm |
| |