/* * Copyright (C) 2011-2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _LIBRENDER_FRAMEBUFFER_H #define _LIBRENDER_FRAMEBUFFER_H #include #include #include #include #include #include #include #include #include "Buffer.h" #include "ColorBuffer.h" #include "Compositor.h" #include "Display.h" #include "DisplaySurface.h" #include "Hwc2.h" #include "PostCommands.h" #include "PostWorker.h" #include "ProcessResources.h" #include "ReadbackWorker.h" #include "VsyncThread.h" #include "aemu/base/AsyncResult.h" #include "aemu/base/EventNotificationSupport.h" #include "aemu/base/HealthMonitor.h" #include "aemu/base/ManagedDescriptor.hpp" #include "aemu/base/Metrics.h" #include "aemu/base/files/Stream.h" #include "aemu/base/synchronization/Lock.h" #include "aemu/base/synchronization/MessageChannel.h" #include "aemu/base/threads/Thread.h" #include "aemu/base/threads/WorkerThread.h" #include "gfxstream/host/Features.h" #if GFXSTREAM_ENABLE_HOST_GLES #include #include #include #include "gl/BufferGl.h" #include "gl/ColorBufferGl.h" #include "gl/CompositorGl.h" #include "gl/DisplaySurfaceGl.h" #include "gl/EmulatedEglConfig.h" #include "gl/EmulatedEglContext.h" #include "gl/EmulatedEglImage.h" #include "gl/EmulatedEglWindowSurface.h" #include "gl/EmulationGl.h" #include "gl/GLESVersionDetector.h" #include "gl/TextureDraw.h" #else #include "GlesCompat.h" #endif // values for 'param' argument of rcGetFBParam #define FB_WIDTH 1 #define FB_HEIGHT 2 #define FB_XDPI 3 #define FB_YDPI 4 #define FB_FPS 5 #define FB_MIN_SWAP_INTERVAL 6 #define FB_MAX_SWAP_INTERVAL 7 #include "render-utils/Renderer.h" #include "render-utils/virtio_gpu_ops.h" #include "render-utils/render_api.h" #include "snapshot/common.h" #include "utils/RenderDoc.h" #include "vulkan/vk_util.h" namespace gfxstream { namespace vk { class DisplayVk; } // namespace vk } // namespace gfxstream namespace gfxstream { using android::base::CreateMetricsLogger; using emugl::HealthMonitor; using emugl::MetricsLogger; struct BufferRef { BufferPtr buffer; }; #if GFXSTREAM_ENABLE_HOST_GLES typedef std::unordered_map ProcOwnedEmulatedEglWindowSurfaces; typedef std::unordered_map ProcOwnedEmulatedEglContexts; typedef std::unordered_map ProcOwnedEmulatedEGLImages; #endif typedef std::unordered_map ProcOwnedColorBuffers; typedef std::unordered_map BufferMap; typedef std::unordered_multiset BufferSet; typedef std::unordered_map ProcOwnedBuffers; typedef std::unordered_map> CallbackMap; typedef std::unordered_map ProcOwnedCleanupCallbacks; // The FrameBuffer class holds the global state of the emulation library on // top of the underlying EGL/GLES implementation. It should probably be // named "Display" instead of "FrameBuffer". // // There is only one global instance, that can be retrieved with getFB(), // and which must be previously setup by calling initialize(). // class FrameBuffer : public android::base::EventNotificationSupport { public: // Initialize the global instance. // |width| and |height| are the dimensions of the emulator GPU display // in pixels. |useSubWindow| is true to indicate that the caller // will use setupSubWindow() to let EmuGL display the GPU content in its // own sub-windows. If false, this means the caller will use // setPostCallback() instead to retrieve the content. // Returns true on success, false otherwise. static bool initialize(int width, int height, gfxstream::host::FeatureSet features, bool useSubWindow, bool egl2egl); // Finalize the instance. static void finalize(); // Setup a sub-window to display the content of the emulated GPU // on-top of an existing UI window. |p_window| is the platform-specific // parent window handle. |wx|, |wy|, |ww| and |wh| are the // dimensions in pixels of the sub-window, relative to the parent window's // coordinate. |fbw| and |fbh| are the dimensions used to initialize // the framebuffer, which may be different from the dimensions of the // sub-window (in which case scaling will be applied automatically). // |dpr| is the device pixel ratio of the monitor, which is needed for // proper panning on high-density displays (like retina) // |zRot| is a rotation angle in degrees, (clockwise in the Y-upwards GL // coordinate space). // // If a sub-window already exists, this function updates the subwindow // and framebuffer properties to match the given values. // // Return true on success, false otherwise. // // NOTE: This can return false for software-only EGL engines like OSMesa. bool setupSubWindow(FBNativeWindowType p_window, int wx, int wy, int ww, int wh, int fbw, int fbh, float dpr, float zRot, bool deleteExisting, bool hideWindow); // Remove the sub-window created by setupSubWindow(), if any. // Return true on success, false otherwise. bool removeSubWindow(); // Return a pointer to the global instance. initialize() must be called // previously, or this will return NULL. static FrameBuffer* getFB() { return s_theFrameBuffer; } // Wait for a FrameBuffer instance to be initialized and ready to use. // This function blocks the caller until there is a valid initialized // object in getFB() and static void waitUntilInitialized(); // Return the emulated GPU display width in pixels. int getWidth() const { return m_framebufferWidth; } // Return the emulated GPU display height in pixels. int getHeight() const { return m_framebufferHeight; } // Set a callback that will be called each time the emulated GPU content // is updated. This can be relatively slow with host-based GPU emulation, // so only do this when you need to. void setPostCallback(Renderer::OnPostCallback onPost, void* onPostContext, uint32_t displayId, bool useBgraReadback = false); // Create a new ColorBuffer instance from this display instance. // |p_width| and |p_height| are its dimensions in pixels. // |p_internalFormat| is the OpenGL format of this color buffer. // |p_frameworkFormat| describes the Android frameework format of this // color buffer, if differing from |p_internalFormat|. // See ColorBuffer::create() for // list of valid values. Note that ColorBuffer instances are reference- // counted. Use openColorBuffer / closeColorBuffer to operate on the // internal count. HandleType createColorBuffer(int p_width, int p_height, GLenum p_internalFormat, FrameworkFormat p_frameworkFormat); // Variant of createColorBuffer except with a particular // handle already assigned. This is for use with // virtio-gpu's RESOURCE_CREATE ioctl. void createColorBufferWithHandle(int p_width, int p_height, GLenum p_internalFormat, FrameworkFormat p_frameworkFormat, HandleType handle, bool linear = false); // Create a new data Buffer instance from this display instance. // The buffer will be backed by a VkBuffer and VkDeviceMemory (if Vulkan // is available). // |size| is the requested size of Buffer in bytes. // |memoryProperty| is the requested memory property bits of the device // memory. HandleType createBuffer(uint64_t size, uint32_t memoryProperty); // Variant of createBuffer except with a particular handle already // assigned and using device local memory. This is for use with // virtio-gpu's RESOURCE_CREATE ioctl for BLOB resources. void createBufferWithHandle(uint64_t size, HandleType handle); // Increment the reference count associated with a given ColorBuffer // instance. |p_colorbuffer| is its handle value as returned by // createColorBuffer(). int openColorBuffer(HandleType p_colorbuffer); // Decrement the reference count associated with a given ColorBuffer // instance. |p_colorbuffer| is its handle value as returned by // createColorBuffer(). Note that if the reference count reaches 0, // the instance is destroyed automatically. void closeColorBuffer(HandleType p_colorbuffer); // Destroy a Buffer created previously. |p_buffer| is its handle value as // returned by createBuffer(). void closeBuffer(HandleType p_colorbuffer); // The caller mustn't refer to this puid before this function returns, i.e. the creation of the // host process pipe must be blocked until this function returns. void createGraphicsProcessResources(uint64_t puid); // The process resource is returned so that we can destroy it on a separate thread. std::unique_ptr removeGraphicsProcessResources(uint64_t puid); // TODO(kaiyili): retire cleanupProcGLObjects in favor of removeGraphicsProcessResources. void cleanupProcGLObjects(uint64_t puid); // Read the content of a given Buffer into client memory. // |p_buffer| is the Buffer's handle value. // |offset| and |size| are the position and size of a slice of the buffer // that will be read. // |bytes| is the address of a caller-provided buffer that will be filled // with the buffer data. void readBuffer(HandleType p_buffer, uint64_t offset, uint64_t size, void* bytes); // Read the content of a given ColorBuffer into client memory. // |p_colorbuffer| is the ColorBuffer's handle value. Similar // to glReadPixels(), this can be a slow operation. // |x|, |y|, |width| and |height| are the position and dimensions of // a rectangle whose pixel values will be transfered to the host. // |format| indicates the format of the pixel data, e.g. GL_RGB or GL_RGBA. // |type| is the type of pixel data, e.g. GL_UNSIGNED_BYTE. // |pixels| is the address of a caller-provided buffer that will be filled // with the pixel data. void readColorBuffer(HandleType p_colorbuffer, int x, int y, int width, int height, GLenum format, GLenum type, void* pixels); // Read the content of a given YUV420_888 ColorBuffer into client memory. // |p_colorbuffer| is the ColorBuffer's handle value. Similar // to glReadPixels(), this can be a slow operation. // |x|, |y|, |width| and |height| are the position and dimensions of // a rectangle whose pixel values will be transfered to the host. // |pixels| is the address of a caller-provided buffer that will be filled // with the pixel data. // |pixles_size| is the size of buffer void readColorBufferYUV(HandleType p_colorbuffer, int x, int y, int width, int height, void* pixels, uint32_t pixels_size); // Update the content of a given Buffer from client data. // |p_buffer| is the Buffer's handle value. // |offset| and |size| are the position and size of a slice of the buffer // that will be updated. // |bytes| is the address of a caller-provided buffer containing the new // buffer data. bool updateBuffer(HandleType p_buffer, uint64_t offset, uint64_t size, void* pixels); // Update the content of a given ColorBuffer from client data. // |p_colorbuffer| is the ColorBuffer's handle value. Similar // to glReadPixels(), this can be a slow operation. // |x|, |y|, |width| and |height| are the position and dimensions of // a rectangle whose pixel values will be transfered to the GPU // |format| indicates the format of the OpenGL buffer, e.g. GL_RGB or // GL_RGBA. |frameworkFormat| indicates the format of the pixel data; if // FRAMEWORK_FORMAT_GL_COMPATIBLE, |format| (OpenGL format) is used. // Otherwise, explicit conversion to |format| is needed. // |type| is the type of pixel data, e.g. GL_UNSIGNED_BYTE. // |pixels| is the address of a buffer containing the new pixel data. // Returns true on success, false otherwise. bool updateColorBuffer(HandleType p_colorbuffer, int x, int y, int width, int height, GLenum format, GLenum type, void* pixels); bool updateColorBufferFromFrameworkFormat(HandleType p_colorbuffer, int x, int y, int width, int height, FrameworkFormat fwkFormat, GLenum format, GLenum type, void* pixels, void* metadata = nullptr); bool getColorBufferInfo(HandleType p_colorbuffer, int* width, int* height, GLint* internalformat, FrameworkFormat* frameworkFormat = nullptr); bool getBufferInfo(HandleType p_buffer, int* size); // Display the content of a given ColorBuffer into the framebuffer's // sub-window. |p_colorbuffer| is a handle value. // |needLockAndBind| is used to indicate whether the operation requires // acquiring/releasing the FrameBuffer instance's lock and binding the // contexts. It should be |false| only when called internally. bool post(HandleType p_colorbuffer, bool needLockAndBind = true); // The callback will always be called; however, the callback may not be called // until after this function has returned. If the callback is deferred, then it // will be dispatched to run on SyncThread. void postWithCallback(HandleType p_colorbuffer, Post::CompletionCallback callback, bool needLockAndBind = true); bool hasGuestPostedAFrame() { return m_guestPostedAFrame; } void resetGuestPostedAFrame() { m_guestPostedAFrame = false; } // Runs the post callback with |pixels| (good for when the readback // happens in a separate place) void doPostCallback(void* pixels, uint32_t displayId); void getPixels(void* pixels, uint32_t bytes, uint32_t displayId); void flushReadPipeline(int displayId); void ensureReadbackWorker(); bool asyncReadbackSupported(); Renderer::ReadPixelsCallback getReadPixelsCallback(); Renderer::FlushReadPixelPipeline getFlushReadPixelPipeline(); // Re-post the last ColorBuffer that was displayed through post(). // This is useful if you detect that the sub-window content needs to // be re-displayed for any reason. bool repost(bool needLockAndBind = true); // Change the rotation of the displayed GPU sub-window. void setDisplayRotation(float zRot) { if (zRot != m_zRot) { m_zRot = zRot; repost(); } } // Changes what coordinate of this framebuffer will be displayed at the // corner of the GPU sub-window. Specifically, |px| and |py| = 0 means // align the bottom-left of the framebuffer with the bottom-left of the // sub-window, and |px| and |py| = 1 means align the top right of the // framebuffer with the top right of the sub-window. Intermediate values // interpolate between these states. void setDisplayTranslation(float px, float py) { // Sanity check the values to ensure they are between 0 and 1 const float x = px > 1.f ? 1.f : (px < 0.f ? 0.f : px); const float y = py > 1.f ? 1.f : (py < 0.f ? 0.f : py); if (x != m_px || y != m_py) { m_px = x; m_py = y; repost(); } } void lockContextStructureRead() { m_contextStructureLock.lockRead(); } void unlockContextStructureRead() { m_contextStructureLock.unlockRead(); } // For use with sync threads and otherwise, any time we need a GL context // not specifically for drawing, but to obtain certain things about // GL state. // It can be unsafe / leaky to change the structure of contexts // outside the facilities the FrameBuffer class provides. void createTrivialContext(HandleType shared, HandleType* contextOut, HandleType* surfOut); void setShuttingDown() { m_shuttingDown = true; } bool isShuttingDown() const { return m_shuttingDown; } bool compose(uint32_t bufferSize, void* buffer, bool post = true); // When false is returned, the callback won't be called. The callback will // be called on the PostWorker thread without blocking the current thread. AsyncResult composeWithCallback(uint32_t bufferSize, void* buffer, Post::CompletionCallback callback); ~FrameBuffer(); void onSave(android::base::Stream* stream, const android::snapshot::ITextureSaverPtr& textureSaver); bool onLoad(android::base::Stream* stream, const android::snapshot::ITextureLoaderPtr& textureLoader); // lock and unlock handles (EmulatedEglContext, ColorBuffer, EmulatedEglWindowSurface) void lock(); void unlock(); float getDpr() const { return m_dpr; } int windowWidth() const { return m_windowWidth; } int windowHeight() const { return m_windowHeight; } float getPx() const { return m_px; } float getPy() const { return m_py; } int getZrot() const { return m_zRot; } bool isVulkanInteropSupported() const { return m_vulkanInteropSupported; } bool isVulkanEnabled() const { return m_vulkanEnabled; } // Saves a screenshot of the previous frame. // nChannels should be 3 (RGB) or 4 (RGBA). // You must provide a pre-allocated buffer of sufficient // size. Returns 0 on success. In the case of failure and if *cPixels != 0 // you can call this function again with a buffer of size *cPixels. cPixels // should usually be at at least desiredWidth * desiredHeight * nChannels. // // In practice the buffer should be > desiredWidth * // desiredHeight * nChannels. // // Note: Do not call this function again if it fails and *cPixels == 0 // swiftshader_indirect does not work with 3 channels // // This function supports rectangle snipping by // providing an |rect| parameter. The default value of {{0,0}, {0,0}} // indicates the users wants to snip the entire screen instead of a // partial screen. // - |rect| represents a rectangle within the screen defined by // desiredWidth and desiredHeight. int getScreenshot(unsigned int nChannels, unsigned int* width, unsigned int* height, uint8_t* pixels, size_t* cPixels, int displayId, int desiredWidth, int desiredHeight, int desiredRotation, Rect rect = {{0, 0}, {0, 0}}); void onLastColorBufferRef(uint32_t handle); ColorBufferPtr findColorBuffer(HandleType p_colorbuffer); BufferPtr findBuffer(HandleType p_buffer); void registerProcessCleanupCallback(void* key, std::function callback); void unregisterProcessCleanupCallback(void* key); const ProcessResources* getProcessResources(uint64_t puid); int createDisplay(uint32_t *displayId); int createDisplay(uint32_t displayId); int destroyDisplay(uint32_t displayId); int setDisplayColorBuffer(uint32_t displayId, uint32_t colorBuffer); int getDisplayColorBuffer(uint32_t displayId, uint32_t* colorBuffer); int getColorBufferDisplay(uint32_t colorBuffer, uint32_t* displayId); int getDisplayPose(uint32_t displayId, int32_t* x, int32_t* y, uint32_t* w, uint32_t* h); int setDisplayPose(uint32_t displayId, int32_t x, int32_t y, uint32_t w, uint32_t h, uint32_t dpi = 0); void getCombinedDisplaySize(int* w, int* h); struct DisplayInfo { uint32_t cb; int32_t pos_x; int32_t pos_y; uint32_t width; uint32_t height; uint32_t dpi; DisplayInfo() : cb(0), pos_x(0), pos_y(0), width(0), height(0), dpi(0){}; DisplayInfo(uint32_t cb, int32_t x, int32_t y, uint32_t w, uint32_t h, uint32_t d) : cb(cb), pos_x(x), pos_y(y), width(w), height(h), dpi(d) {} }; // Inline with MultiDisplay::s_invalidIdMultiDisplay static const uint32_t s_invalidIdMultiDisplay = 0xFFFFFFAB; static const uint32_t s_maxNumMultiDisplay = 11; HandleType getLastPostedColorBuffer() { return m_lastPostedColorBuffer; } void waitForGpuVulkan(uint64_t deviceHandle, uint64_t fenceHandle); void asyncWaitForGpuVulkanWithCb(uint64_t deviceHandle, uint64_t fenceHandle, FenceCompletionCallback cb); void asyncWaitForGpuVulkanQsriWithCb(uint64_t image, FenceCompletionCallback cb); void waitForGpuVulkanQsri(uint64_t image); bool platformImportResource(uint32_t handle, uint32_t info, void* resource); void setGuestManagedColorBufferLifetime(bool guestManaged); std::unique_ptr borrowColorBufferForComposition(uint32_t colorBufferHandle, bool colorBufferIsTarget); std::unique_ptr borrowColorBufferForDisplay(uint32_t colorBufferHandle); HealthMonitor<>* getHealthMonitor() { return m_healthMonitor.get(); } emugl::MetricsLogger& getMetricsLogger() { return *m_logger; } void logVulkanOutOfMemory(VkResult result, const char* function, int line, std::optional allocationSize = std::nullopt); void setVsyncHz(int vsyncHz); void scheduleVsyncTask(VsyncThread::VsyncTask task); void setDisplayConfigs(int configId, int w, int h, int dpiX, int dpiY); void setDisplayActiveConfig(int configId); const int getDisplayConfigsCount(); const int getDisplayConfigsParam(int configId, EGLint param); const int getDisplayActiveConfig(); bool flushColorBufferFromVk(HandleType colorBufferHandle); bool flushColorBufferFromVkBytes(HandleType colorBufferHandle, const void* bytes, size_t bytesSize); bool invalidateColorBufferForVk(HandleType colorBufferHandle); #if GFXSTREAM_ENABLE_HOST_GLES // Retrieves the color buffer handle associated with |p_surface|. // Returns 0 if there is no such handle. HandleType getEmulatedEglWindowSurfaceColorBufferHandle(HandleType p_surface); // createTrivialContext(), but with a m_pbufContext // as shared, and not adding itself to the context map at all. void createSharedTrivialContext(EGLContext* contextOut, EGLSurface* surfOut); void destroySharedTrivialContext(EGLContext context, EGLSurface surf); // Attach a ColorBuffer to a EmulatedEglWindowSurface instance. // See the documentation for EmulatedEglWindowSurface::setColorBuffer(). // |p_surface| is the target EmulatedEglWindowSurface's handle value. // |p_colorbuffer| is the ColorBuffer handle value. // Returns true on success, false otherwise. bool setEmulatedEglWindowSurfaceColorBuffer(HandleType p_surface, HandleType p_colorbuffer); // Return the list of configs available from this display. const gl::EmulatedEglConfigList* getConfigs() const; // Retrieve the GL strings of the underlying EGL/GLES implementation. // On return, |*vendor|, |*renderer| and |*version| will point to strings // that are owned by the instance (and must not be freed by the caller). void getGLStrings(const char** vendor, const char** renderer, const char** version) const { *vendor = m_graphicsAdapterVendor.c_str(); *renderer = m_graphicsAdapterName.c_str(); *version = m_graphicsApiVersion.c_str(); } // Create a new EmulatedEglContext instance for this display instance. // |p_config| is the index of one of the configs returned by getConfigs(). // |p_share| is either EGL_NO_CONTEXT or the handle of a shared context. // |version| specifies the GLES version as a GLESApi enum. // Return a new handle value, which will be 0 in case of error. HandleType createEmulatedEglContext(int p_config, HandleType p_share, gl::GLESApi version = gl::GLESApi_CM); // Destroy a given EmulatedEglContext instance. |p_context| is its handle // value as returned by createEmulatedEglContext(). void destroyEmulatedEglContext(HandleType p_context); // Create a new EmulatedEglWindowSurface instance from this display instance. // |p_config| is the index of one of the configs returned by getConfigs(). // |p_width| and |p_height| are the window dimensions in pixels. // Return a new handle value, or 0 in case of error. HandleType createEmulatedEglWindowSurface(int p_config, int p_width, int p_height); // Destroy a given EmulatedEglWindowSurface instance. |p_surcace| is its // handle value as returned by createEmulatedEglWindowSurface(). void destroyEmulatedEglWindowSurface(HandleType p_surface); // Returns the set of ColorBuffers destroyed (for further cleanup) std::vector destroyEmulatedEglWindowSurfaceLocked(HandleType p_surface); void createEmulatedEglFenceSync(EGLenum type, int destroyWhenSignaled, uint64_t* outSync = nullptr, uint64_t* outSyncThread = nullptr); // Call this function when a render thread terminates to destroy all // resources it created. Necessary to avoid leaking host resources // when a guest application crashes, for example. void drainGlRenderThreadResources(); // Call this function when a render thread terminates to destroy all // the remaining contexts it created. Necessary to avoid leaking host // contexts when a guest application crashes, for example. void drainGlRenderThreadContexts(); // Call this function when a render thread terminates to destroy all // remaining window surface it created. Necessary to avoid leaking // host buffers when a guest application crashes, for example. void drainGlRenderThreadSurfaces(); gl::EmulationGl& getEmulationGl(); bool hasEmulationGl() const { return m_emulationGl != nullptr; } // Return the host EGLDisplay used by this instance. EGLDisplay getDisplay() const; EGLSurface getWindowSurface() const; EGLContext getContext() const; EGLConfig getConfig() const; EGLContext getGlobalEGLContext() const; // Return a render context pointer from its handle gl::EmulatedEglContextPtr getContext_locked(HandleType p_context); // Return a color buffer pointer from its handle gl::EmulatedEglWindowSurfacePtr getWindowSurface_locked(HandleType p_windowsurface); // Return a TextureDraw instance that can be used with this surfaces // and windows created by this instance. gl::TextureDraw* getTextureDraw() const; bool isFastBlitSupported() const; void disableFastBlitForTesting(); // Create an eglImage and return its handle. Reference: // https://www.khronos.org/registry/egl/extensions/KHR/EGL_KHR_image_base.txt HandleType createEmulatedEglImage(HandleType context, EGLenum target, GLuint buffer); // Call the implementation of eglDestroyImageKHR, return if succeeds or // not. Reference: // https://www.khronos.org/registry/egl/extensions/KHR/EGL_KHR_image_base.txt EGLBoolean destroyEmulatedEglImage(HandleType image); // Copy the content of a EmulatedEglWindowSurface's Pbuffer to its attached // ColorBuffer. See the documentation for // EmulatedEglWindowSurface::flushColorBuffer(). // |p_surface| is the target WindowSurface's handle value. // Returns true on success, false on failure. bool flushEmulatedEglWindowSurfaceColorBuffer(HandleType p_surface); gl::GLESDispatchMaxVersion getMaxGLESVersion(); // Fill GLES usage protobuf void fillGLESUsages(android_studio::EmulatorGLESUsages*); void* platformCreateSharedEglContext(void); bool platformDestroySharedEglContext(void* context); bool flushColorBufferFromGl(HandleType colorBufferHandle); bool invalidateColorBufferForGl(HandleType colorBufferHandle); ContextHelper* getPbufferSurfaceContextHelper() const; // Bind the current context's EGL_TEXTURE_2D texture to a ColorBuffer // instance's EGLImage. This is intended to implement // glEGLImageTargetTexture2DOES() for all GLES versions. // |p_colorbuffer| is the ColorBuffer's handle value. // Returns true on success, false on failure. bool bindColorBufferToTexture(HandleType p_colorbuffer); bool bindColorBufferToTexture2(HandleType p_colorbuffer); // Bind the current context's EGL_RENDERBUFFER_OES render buffer to this // ColorBuffer's EGLImage. This is intended to implement // glEGLImageTargetRenderbufferStorageOES() for all GLES versions. // |p_colorbuffer| is the ColorBuffer's handle value. // Returns true on success, false on failure. bool bindColorBufferToRenderbuffer(HandleType p_colorbuffer); // Equivalent for eglMakeCurrent() for the current display. // |p_context|, |p_drawSurface| and |p_readSurface| are the handle values // of the context, the draw surface and the read surface, respectively. // Returns true on success, false on failure. // Note: if all handle values are 0, this is an unbind operation. bool bindContext(HandleType p_context, HandleType p_drawSurface, HandleType p_readSurface); // create a Y texture and a UV texture with width and height, the created // texture ids are stored in textures respectively void createYUVTextures(uint32_t type, uint32_t count, int width, int height, uint32_t* output); void destroyYUVTextures(uint32_t type, uint32_t count, uint32_t* textures); void updateYUVTextures(uint32_t type, uint32_t* textures, void* privData, void* func); void swapTexturesAndUpdateColorBuffer(uint32_t colorbufferhandle, int x, int y, int width, int height, uint32_t format, uint32_t type, uint32_t texture_type, uint32_t* textures); // Reads back the raw color buffer to |pixels| // if |pixels| is not null. // Always returns in |numBytes| how many bytes were // planned to be transmitted. // |numBytes| is not an input parameter; // fewer or more bytes cannot be specified. // If the framework format is YUV, it will read // back as raw YUV data. bool readColorBufferContents(HandleType p_colorbuffer, size_t* numBytes, void* pixels); void waitForGpu(uint64_t eglsync); void asyncWaitForGpuWithCb(uint64_t eglsync, FenceCompletionCallback cb); const gl::EGLDispatch* getEglDispatch(); const gl::GLESv2Dispatch* getGles2Dispatch(); #endif const gfxstream::host::FeatureSet& getFeatures() const { return m_features; } private: FrameBuffer(int p_width, int p_height, gfxstream::host::FeatureSet features, bool useSubWindow); // Requires the caller to hold the m_colorBufferMapLock until the new handle is inserted into of // the object handle maps. HandleType genHandle_locked(); bool removeSubWindow_locked(); // Returns the set of ColorBuffers destroyed (for further cleanup) std::vector cleanupProcGLObjects_locked(uint64_t puid, bool forced = false); void markOpened(ColorBufferRef* cbRef); // Returns true if the color buffer was erased. bool closeColorBufferLocked(HandleType p_colorbuffer, bool forced = false); // Returns true if this was the last ref and we need to destroy stuff. bool decColorBufferRefCountLocked(HandleType p_colorbuffer); // Decrease refcount but not destroy the object. // Mainly used in post thread, when we need to destroy the object but cannot in post thread. void decColorBufferRefCountNoDestroy(HandleType p_colorbuffer); // Close all expired color buffers for real. // Treat all delayed color buffers as expired if forced=true void performDelayedColorBufferCloseLocked(bool forced = false); void eraseDelayedCloseColorBufferLocked(HandleType cb, uint64_t ts); AsyncResult postImpl(HandleType p_colorbuffer, Post::CompletionCallback callback, bool needLockAndBind = true, bool repaint = false); bool postImplSync(HandleType p_colorbuffer, bool needLockAndBind = true, bool repaint = false); void setGuestPostedAFrame() { m_guestPostedAFrame = true; fireEvent({FrameBufferChange::FrameReady, mFrameNumber++}); } HandleType createColorBufferWithHandleLocked(int p_width, int p_height, GLenum p_internalFormat, FrameworkFormat p_frameworkFormat, HandleType handle, bool linear = false); HandleType createBufferWithHandleLocked(int p_size, HandleType handle, uint32_t memoryProperty); void recomputeLayout(); void setDisplayPoseInSkinUI(int totalHeight); void sweepColorBuffersLocked(); std::future blockPostWorker(std::future continueSignal); private: static FrameBuffer* s_theFrameBuffer; static HandleType s_nextHandle; gfxstream::host::FeatureSet m_features; int m_x = 0; int m_y = 0; int m_framebufferWidth = 0; int m_framebufferHeight = 0; std::atomic_int m_windowWidth = 0; std::atomic_int m_windowHeight = 0; // When zoomed in, the size of the content is bigger than the window size, and we only // display / store a portion of it. int m_windowContentFullWidth = 0; int m_windowContentFullHeight = 0; float m_dpr = 0; bool m_useSubWindow = false; bool m_fpsStats = false; bool m_perfStats = false; int m_statsNumFrames = 0; long long m_statsStartTime = 0; android::base::Thread* m_perfThread; android::base::Lock m_lock; android::base::ReadWriteLock m_contextStructureLock; android::base::Lock m_colorBufferMapLock; uint64_t mFrameNumber; FBNativeWindowType m_nativeWindow = 0; ColorBufferMap m_colorbuffers; BufferMap m_buffers; // A collection of color buffers that were closed without any usages // (|opened| == false). // // If a buffer reached |refcount| == 0 while not being |opened|, instead of // deleting it we remember the timestamp when this happened. Later, we // check if the buffer stayed unopened long enough and if it did, we delete // it permanently. On the other hand, if the color buffer was used then // we don't care about timestamps anymore. // // Note: this collection is ordered by |ts| field. struct ColorBufferCloseInfo { uint64_t ts; // when we got the close request. HandleType cbHandle; // 0 == already closed, do nothing }; using ColorBufferDelayedClose = std::vector; ColorBufferDelayedClose m_colorBufferDelayedCloseList; EGLNativeWindowType m_subWin = {}; HandleType m_lastPostedColorBuffer = 0; float m_zRot = 0; float m_px = 0; float m_py = 0; // Async readback enum class ReadbackCmd { Init = 0, GetPixels = 1, AddRecordDisplay = 2, DelRecordDisplay = 3, Exit = 4, }; struct Readback { ReadbackCmd cmd; uint32_t displayId; void* pixelsOut; uint32_t bytes; uint32_t width; uint32_t height; }; android::base::WorkerProcessingResult sendReadbackWorkerCmd( const Readback& readback); bool m_guestPostedAFrame = false; struct onPost { Renderer::OnPostCallback cb; void* context; uint32_t displayId; uint32_t width; uint32_t height; unsigned char* img = nullptr; bool readBgra; ~onPost() { if (img) { delete[] img; img = nullptr; } } }; std::map m_onPost; ReadbackWorker* m_readbackWorker = nullptr; android::base::WorkerThread m_readbackThread; std::atomic_bool m_readbackThreadStarted = false; std::string m_graphicsAdapterVendor; std::string m_graphicsAdapterName; std::string m_graphicsApiVersion; std::string m_graphicsApiExtensions; std::string m_graphicsDeviceExtensions; std::unordered_map> m_procOwnedResources; // Flag set when emulator is shutting down. bool m_shuttingDown = false; // When this feature is enabled, open/close operations from gralloc in guest // will no longer control the reference counting of color buffers on host. // Instead, it will be managed by a file descriptor in the guest kernel. In // case all the native handles in guest are destroyed, the pipe will be // automatically closed by the kernel. We only need to do reference counting // for color buffers attached in window surface. bool m_refCountPipeEnabled = false; // When this feature is enabled, and m_refCountPipeEnabled == false, color // buffer close operations will immediately close the color buffer if host // refcount hits 0. This is for use with guest kernels where the color // buffer is already tied to a file descriptor in the guest kernel. bool m_noDelayCloseColorBufferEnabled = false; std::unique_ptr m_postWorker = {}; std::atomic_bool m_postThreadStarted = false; android::base::WorkerThread m_postThread; android::base::WorkerProcessingResult postWorkerFunc(Post& post); std::future sendPostWorkerCmd(Post post); bool m_vulkanInteropSupported = false; bool m_vulkanEnabled = false; bool m_guestUsesAngle = false; // Whether the guest manages ColorBuffer lifetime // so we don't need refcounting on the host side. bool m_guestManagedColorBufferLifetime = false; android::base::MessageChannel mOutstandingColorBufferDestroys; Compositor* m_compositor = nullptr; bool m_useVulkanComposition = false; vk::VkEmulation* m_emulationVk = nullptr; // The implementation for Vulkan native swapchain. Only initialized when useVulkan is set when // calling FrameBuffer::initialize(). DisplayVk is actually owned by VkEmulation. vk::DisplayVk* m_displayVk = nullptr; VkInstance m_vkInstance = VK_NULL_HANDLE; std::unique_ptr m_renderDoc = nullptr; // TODO(b/233939967): Refactor to create DisplayGl and DisplaySurfaceGl // and remove usage of non-generic DisplayVk. Display* m_display; std::unique_ptr m_displaySurface; // CompositorGl. // TODO: update RenderDoc to be a DisplaySurfaceUser. std::vector m_displaySurfaceUsers; // UUIDs of physical devices for Vulkan and GLES, respectively. In most // cases, this determines whether we can support zero-copy interop. using VkUuid = std::array; VkUuid m_vulkanUUID{}; // Tracks platform EGL contexts that have been handed out to other users, // indexed by underlying native EGL context object. std::unique_ptr m_logger; std::unique_ptr> m_healthMonitor; int m_vsyncHz = 60; // Vsync thread. std::unique_ptr m_vsyncThread = {}; struct DisplayConfig{ int w; int h; int dpiX; int dpiY; DisplayConfig() {} DisplayConfig(int w, int h, int x, int y) : w(w), h(h), dpiX(x), dpiY(y) {} }; std::map mDisplayConfigs; int mDisplayActiveConfigId = -1; std::unique_ptr m_emulationGl; // The host associates color buffers with guest processes for memory // cleanup. Guest processes are identified with a host generated unique ID. // TODO(kaiyili): move all those resources to the ProcessResources struct. ProcOwnedColorBuffers m_procOwnedColorBuffers; ProcOwnedCleanupCallbacks m_procOwnedCleanupCallbacks; #if GFXSTREAM_ENABLE_HOST_GLES gl::EmulatedEglContextMap m_contexts; gl::EmulatedEglImageMap m_images; gl::EmulatedEglWindowSurfaceMap m_windows; std::unordered_map m_EmulatedEglWindowSurfaceToColorBuffer; ProcOwnedEmulatedEGLImages m_procOwnedEmulatedEglImages; ProcOwnedEmulatedEglContexts m_procOwnedEmulatedEglContexts; ProcOwnedEmulatedEglWindowSurfaces m_procOwnedEmulatedEglWindowSurfaces; gl::DisplayGl* m_displayGl = nullptr; struct PlatformEglContextInfo { EGLContext context; EGLSurface surface; }; std::unordered_map m_platformEglContexts; #endif }; } // namespace gfxstream #endif