diff --git a/build/gn/BUILD.gn b/build/gn/BUILD.gn index 61fb063a457a1cab4ad40d2d465429d4f677e900..c94879108ad2608b94123c377b155dcd612c4937 100644 --- a/build/gn/BUILD.gn +++ b/build/gn/BUILD.gn @@ -32,6 +32,8 @@ group("ft_test") { "//display_server/drivers/hal/test:drm_backend_test", "//display_server/frameworks/surface/test/ft_build:test", "//display_server/rosen/samples/composer/ft_build:hello_composer", - "//display_server/rosen/modules/render_service_client/test/ft_build:render_service_client_rs_demo" + "//display_server/rosen/modules/render_service_client/test/ft_build:render_service_client_rs_demo", + + "//display_server/drivers/hal/test:gpu_backend_test", ] } diff --git a/display_server/drivers/hal/drm_backend/display_device/drm_display.cpp b/display_server/drivers/hal/drm_backend/display_device/drm_display.cpp index 9f1c359a6624c6133d1f896e9fdfbdf2880af464..1f8be31328285540cb0ebd4d3ef4ceca585de6ed 100644 --- a/display_server/drivers/hal/drm_backend/display_device/drm_display.cpp +++ b/display_server/drivers/hal/drm_backend/display_device/drm_display.cpp @@ -497,7 +497,6 @@ int32_t DrmDisplay::Commit(int32_t *fence) return DISPLAY_NULL_PTR; } - // const DrmFrameBuffer *fb = reservedFb_.get(); const DrmFrameBuffer *fb = layer->GetFrameBuffer(drmFd_); if (fb == nullptr) { LOG_ERROR("DrmDisplay::Commit: failed to get framebuffer, use reservedFb_ instead."); diff --git a/display_server/drivers/hal/drm_backend/display_device/drm_frame_buffer.cpp b/display_server/drivers/hal/drm_backend/display_device/drm_frame_buffer.cpp index 56b538ae3cca9282715abfeba2d4df21684c4874..8244fd80b83a7ac36906ee4b6e3a75645cfe8e52 100644 --- a/display_server/drivers/hal/drm_backend/display_device/drm_frame_buffer.cpp +++ b/display_server/drivers/hal/drm_backend/display_device/drm_frame_buffer.cpp @@ -37,21 +37,13 @@ bool AddFb(int drmFd, uint32_t fbHandle, FrameBufferInfo &fbInfo) pitches[0] = fbInfo.stride; offsets[0] = 0; - if (drmModeAddFB2( - drmFd, - fbInfo.width, - fbInfo.height, - DRM_FORMAT_XRGB8888, // need use DRM_FORMAT_XRGB8888 - handles, - pitches, - offsets, - &fbInfo.fbId, - 0) != 0) { - LOG_ERROR("drmModeAddFB2 failed, error: %{public}s", ErrnoToString(errno).c_str()); + printf("AddFb: fd=%d, width=%u, height=%u, pixel_format=DRM_FORMAT_XRGB8888, handle=%u, pitch=%u, offset=%u, fbId=%u\n", + drmFd, fbInfo.width, fbInfo.height, handles[0], pitches[0], offsets[0], fbInfo.fbId); + if (drmModeAddFB2(drmFd, fbInfo.width, fbInfo.height, DRM_FORMAT_XRGB8888, // need use DRM_FORMAT_XRGB8888 + handles, pitches, offsets, &fbInfo.fbId, 0) != 0) { + printf("drmModeAddFB2 failed, error: %s\n", ErrnoToString(errno).c_str()); return false; } - LOG_DEBUG("AddFb: fd=%{public}d, width=%{public}u, height=%{public}u, pixel_format=DRM_FORMAT_XRGB8888, handle=%{public}u, pitch=%{public}u, offset=%{public}u, fbId=%{public}u", - drmFd, fbInfo.width, fbInfo.height, handles[0], pitches[0], offsets[0], fbInfo.fbId); return true; } diff --git a/display_server/drivers/hal/drm_backend/display_device/drm_layer.cpp b/display_server/drivers/hal/drm_backend/display_device/drm_layer.cpp index b47d15407116470845a075db4f73c0ef1e1fe56e..4229b9b5e3da68dafcc9b2fa82da646dfe09d842 100644 --- a/display_server/drivers/hal/drm_backend/display_device/drm_layer.cpp +++ b/display_server/drivers/hal/drm_backend/display_device/drm_layer.cpp @@ -21,10 +21,6 @@ namespace oewm { namespace drm { DrmFrameBuffer *DrmLayer::GetFrameBuffer(int drmFd) { - // if (currentFrameBuffer_ != nullptr) { - // return currentFrameBuffer_.get(); - // } - if (IsInvalidFd(drmFd)) { LOG_ERROR("DrmLayer::GetFrameBuffer: invalid drm fd"); return nullptr; diff --git a/display_server/drivers/hal/test/BUILD.gn b/display_server/drivers/hal/test/BUILD.gn index c4dc77158035ceaf8fd1c09eefbaa2097cfde356..4c23998b58bc2c29d55c540babbb602bedab512e 100644 --- a/display_server/drivers/hal/test/BUILD.gn +++ b/display_server/drivers/hal/test/BUILD.gn @@ -32,3 +32,24 @@ ft_executable("drm_backend_test") { "//display_server/drivers/hal:hal_public_config" ] } + +ft_executable("gpu_backend_test") { + testonly = true + + sources = [ + "system_test/gpu_backend_test.cpp" + ] + + deps = [ + "//display_server/drivers/hal/drm_backend:drm_backend", + "//display_server/drivers/hal/base:hal_base", + "//display_server/utils/sync_fence/ft_build:sync_fence", + "//build/gn/configs/system_libs:ipc_core", + ] + + configs = [ + "//display_server/drivers/hal:hal_public_config" + ] + libs = [ "EGL", "GLESv2" ] +} + diff --git a/display_server/drivers/hal/test/system_test/gpu_backend_test.cpp b/display_server/drivers/hal/test/system_test/gpu_backend_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8688995b1af64eae791fd483d947de1c2b563842 --- /dev/null +++ b/display_server/drivers/hal/test/system_test/gpu_backend_test.cpp @@ -0,0 +1,337 @@ +/* + * Copyright (c) 2023 Huawei Technologies Co., Ltd. + * 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 + +#include "display_device.h" +#include "event_loop/event_loop.h" +#include "hdi_display.h" +#include "hdi_session.h" +#include "sync_fence.h" +#include "allocator_controller.h" +#include +#include +#include + +oewm::HDI::DISPLAY::HdiSession& g_session = oewm::HDI::DISPLAY::HdiSession::GetInstance(); +oewm::HDI::DISPLAY::AllocatorController& g_alloc_controller = oewm::HDI::DISPLAY::AllocatorController::GetInstance(); +oewm::EventLoop g_mainLoop = oewm::EventLoop(); + +bool DestoryBufferHandle(BufferHandle **handle); + +struct FrameBuffer { + BufferHandle *handle; +}; + +class Screen { +public: + ~Screen() noexcept { + if (fb[0]) { + DestoryBufferHandle(&fb[0]->handle); + } + } + static void OnVsync(uint32_t sequence, uint64_t timestamp, void *data); + +public: + uint32_t devId = ~0x0; + bool firstFrame = false; + uint32_t fbIdx = 0; + std::shared_ptr fb[2]; +}; + +std::unordered_map g_screens; +static EGLDisplay defaultDisplay; +static struct gbm_device *gbm_device; +static EGLContext context; +static struct gbm_surface *gbm_surface; +static EGLSurface egl_surface; +static BufferHandle tmpBufferHandle; + +EGLConfig GetEGLConfig() +{ + EGLint egl_config_attribs[] = { + EGL_BUFFER_SIZE, 32, //EGL_BUFFER_SIZE:指定缓冲区的位数为32位。 + EGL_DEPTH_SIZE, EGL_DONT_CARE, //EGL_DEPTH_SIZE:深度缓冲区大小,使用EGL_DONT_CARE表示不关心具体大小。 + EGL_STENCIL_SIZE, EGL_DONT_CARE, //EGL_STENCIL_SIZE:模板缓冲区大小 + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, //EGL_RENDERABLE_TYPE:指定可渲染的类型为OpenGL ES 2.0 + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, //EGL_SURFACE_TYPE:指定表面类型为窗口。 + EGL_NONE, //EGL_NONE:属性数组的结束标志。 + }; + + EGLint num_configs; //调用eglGetConfigs函数获取系统中可用的EGL配置数量,将结果保存在num_configs变量中 + assert(eglGetConfigs(defaultDisplay, NULL, 0, &num_configs) == EGL_TRUE); + + EGLConfig *configs = (EGLConfig *)malloc(num_configs * sizeof(EGLConfig)); + + assert(eglChooseConfig(defaultDisplay, egl_config_attribs, + configs, num_configs, &num_configs) == EGL_TRUE); + assert(num_configs); //确保至少存在一个满足条件的配置 + printf("num config %d\n", num_configs); + + for (int i = 0; i < num_configs; ++i) { + EGLint gbm_format; + + assert(eglGetConfigAttrib(defaultDisplay, configs[i], + EGL_NATIVE_VISUAL_ID, &gbm_format) == EGL_TRUE); + printf("gbm format %x\n", gbm_format); + if (gbm_format == GBM_FORMAT_ARGB8888) { + EGLConfig ret = configs[i]; + free(configs); + return ret; + } + } + // not find config, exit. + abort(); +} + +struct gbm_bo* SwapBuffer(BufferHandle *handle) +{ + //交换EGL表面的前后缓冲区。 + eglSwapBuffers (defaultDisplay, egl_surface); + + //锁定GBM表面的前端缓冲区,以便进行后续操作。 + struct gbm_bo *bo = gbm_surface_lock_front_buffer (gbm_surface); + if (bo == nullptr) { + printf("gbm bo is null\n"); + return nullptr; + } + //获取前端缓冲区的句柄 + handle->key = gbm_bo_get_handle(bo).u32; + handle->stride = gbm_bo_get_stride(bo); + handle->size = handle->stride * handle->height; + handle->format = gbm_bo_get_format(bo); + return bo; +} + +static struct gbm_bo *previous_bo = NULL; +static uint32_t previous_fb; + +void ReleaseBuffer(struct gbm_bo* bo) +{ + if (previous_bo) { //检查是否存在前一个帧缓冲区对象。 + //释放前一个GBM表面的缓冲区。 + gbm_surface_release_buffer (gbm_surface, previous_bo); + } + //更新前一个帧缓冲区对象为当前帧缓冲区对象 + previous_bo = bo; +} + +bool InitEGL(uint32_t devId, BufferHandle **handle) +{ + printf("InitEGL\n"); + + /* Get Display modes */ + std::vector displayModeInfos = {}; + uint32_t num = 0; + + int32_t ret = g_session.CallDisplayFunction( + devId, + &oewm::HDI::DISPLAY::HdiDisplay::GetDisplaySupportedModes, + &num, + (DisplayModeInfo*)nullptr + ); + if (ret != DISPLAY_SUCCESS) { + printf("CreateBuffer: Failed to get display supported modes, ret=%d\n", ret); + return false; + } + if (num <= 0) { + printf("CreateBuffer: display modes is %d, exited.\n", num); + return false; + } + printf("CreateBuffer: display modes num=%d\n", num); + + displayModeInfos.resize(num); + ret = g_session.CallDisplayFunction( + devId, + &oewm::HDI::DISPLAY::HdiDisplay::GetDisplaySupportedModes, + &num, + displayModeInfos.data() + ); + if (ret != DISPLAY_SUCCESS) { + printf("CreateBuffer: Failed to get screen supported modes, ret=%d\n", ret); + return false; + } + + /* Alloc buffer for framebuffer */ + // Choose mode + static const uint32_t DEFAULT_MODE_INDEX = 0; + uint32_t width = displayModeInfos[DEFAULT_MODE_INDEX].width; + uint32_t height = displayModeInfos[DEFAULT_MODE_INDEX].height; + ret = g_session.CallDisplayFunction( + devId, + &oewm::HDI::DISPLAY::HdiDisplay::SetDisplayMode, + DEFAULT_MODE_INDEX); + if (ret != DISPLAY_SUCCESS) { + printf("Draw: Failed to set display mode, ret=%d\n", ret); + return false; + } + printf("CreateBuffer: choose display mode 0 to create fb: width=%d, height=%d.\n", width, height); + + gbm_device = g_session.GetDisplayDevice()->GetGbmDevice(); + defaultDisplay = eglGetDisplay(gbm_device); + int major, minor; + eglInitialize(defaultDisplay, &major, &minor); + printf("EGL version:%d.%d\n", major, minor); + + eglBindAPI(EGL_OPENGL_ES2_BIT); + EGLConfig config = GetEGLConfig(); + context = eglCreateContext (defaultDisplay, config, EGL_NO_CONTEXT, NULL); + + // create the GBM and EGL surface + gbm_surface = gbm_surface_create (gbm_device, width, height, GBM_BO_FORMAT_XRGB8888, GBM_BO_USE_LINEAR|GBM_BO_USE_SCANOUT|GBM_BO_USE_RENDERING); + //创建EGL窗口表面对象,将GBM表面与EGL绑定 + egl_surface = eglCreateWindowSurface (defaultDisplay, config, gbm_surface, NULL); + //将OpenGL上下文与EGL表面进行绑定,使其成为当前上下文。 + eglMakeCurrent (defaultDisplay, egl_surface, egl_surface, context); + + *handle = &tmpBufferHandle; + tmpBufferHandle.virAddr = nullptr; + tmpBufferHandle.height= height; + tmpBufferHandle.width = width; + + return true; +} + +void DrawBaseColor(float progress) +{ + glClearColor (1.0f-progress, progress, 0.0, 1.0); + glClear (GL_COLOR_BUFFER_BIT); +} + +void SignalHandler(int signum) { + printf("Interrupt signal (%d) received.\n", signum); + + g_mainLoop.Stop(); + printf("Stop main loop done.\n"); + + for (auto& screen : g_screens) { + if (screen.second) { + delete screen.second; + } + } + + exit(signum); +} + +bool DestoryBufferHandle(BufferHandle **handle) +{ + eglDestroySurface (defaultDisplay, egl_surface); + gbm_surface_destroy (gbm_surface); + eglDestroyContext (defaultDisplay, context); + eglTerminate (defaultDisplay); + gbm_device_destroy (gbm_device); + + return true; +} + +void Screen::OnVsync(uint32_t sequence, uint64_t timestamp, void *data) +{ + Screen *screen = static_cast(data); + if (screen == nullptr) { + printf("OnVSync: screen is null\n"); + return; + } + + // Do draw in main loop + g_mainLoop.RunInLoop([screen, sequence, timestamp]() { + uint32_t devId = screen->devId; + int32_t fenceFd = -1; + int32_t ret; + + // Create two framebuffers on first frame + if (screen->firstFrame) { + if (screen->fb[0] == nullptr) { + screen->fb[0] = std::make_shared(); + InitEGL(devId, &(screen->fb[0]->handle)); + } + } + screen->firstFrame = false; + + // Fill fb with plain color + if (screen->fbIdx == 100) { + screen->fbIdx = 0; + } + DrawBaseColor(screen->fbIdx / 100.0); + screen->fbIdx++; + printf("OnVSync %d: screen devId=%d, sequence=%u, timestamp=%lu\n", screen->fbIdx, screen->devId, sequence, timestamp); + usleep(100000); + + // swap buffer + struct gbm_bo *bo = SwapBuffer(screen->fb[0]->handle); + + // Set fb as screen's current buffer + ret = g_session.CallDisplayFunction( + devId, + &oewm::HDI::DISPLAY::HdiDisplay::SetDisplayClientBuffer, + static_cast(screen->fb[0]->handle), + fenceFd); + if (ret != DISPLAY_SUCCESS) { + printf("Draw: Failed to set display client buffer, ret=%d\n", ret); + return; + } + + // Commit + ret = g_session.CallDisplayFunction( + devId, + &oewm::HDI::DISPLAY::HdiDisplay::Commit, + &fenceFd); + if (fenceFd >= 0) { + auto fence = OHOS::SyncFence(fenceFd); + } else { + auto fence = OHOS::SyncFence(-1); + } + + ReleaseBuffer(bo); + }); +} + +static void OnHotPlug(uint32_t devId, bool connected, void *data) +{ + printf("OnHotPlug: screen devId=%d, connected=%s\n", devId, connected ? "True" : "False"); + + // Store screen + Screen* screen = new Screen(); + screen->devId = devId; + screen->firstFrame = true; + g_screens[devId] = screen; + + // Register VSync callback + int32_t ret = g_session.CallDisplayFunction( + devId, + &oewm::HDI::DISPLAY::HdiDisplay::RegDisplayVBlankCallback, + Screen::OnVsync, + static_cast(g_screens.at(devId)) + ); + if (ret != DISPLAY_SUCCESS) { + printf("OnHotPlug: Failed to Register VSync callback, ret=%d\n", ret); + return; + } +} + +int main() +{ + signal(SIGINT, SignalHandler); + + printf("session pointer in main: %p, displays size : %lu.", &g_session, g_session.GetDisplayDevice()->GetDisplays().size()); + g_alloc_controller.Init(); + + // Register HotPlug callback + g_session.RegHotPlugCallback(OnHotPlug, nullptr); + + // Start main loop + g_mainLoop.Start(); + + return 0; +}