blob: f72fdcf6effabd4e528792a7c9b32e2bbfd59ab8 [file] [log] [blame]
/*
* Copyright (C) 2011 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 <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES/gl.h>
#include <GLES3/gl3.h>
#include <memory>
#include <unordered_map>
#include <unordered_set>
#include "BorrowedImage.h"
#include "ContextHelper.h"
#include "FrameworkFormats.h"
#include "Handle.h"
#include "Hwc2.h"
#include "aemu/base/ManagedDescriptor.hpp"
#include "aemu/base/files/Stream.h"
#include "render-utils/Renderer.h"
// From ANGLE "src/common/angleutils.h"
#define GL_BGR10_A2_ANGLEX 0x6AF9
// A class used to model a guest color buffer, and used to implement several
// related things:
//
// - Every gralloc native buffer with HW read or write requirements will
// allocate a host ColorBufferGl instance. When gralloc_lock() is called,
// the guest will use ColorBufferGl::readPixels() to read the current content
// of the buffer. When gralloc_unlock() is later called, it will call
// ColorBufferGl::subUpdate() to send the updated pixels.
//
// - Every guest window EGLSurface is implemented by a host PBuffer
// (see WindowSurface.h) that can have a ColorBufferGl instance attached to
// it (through WindowSurface::attachColorBuffer()). When such an attachment
// exists, WindowSurface::flushColorBuffer() will copy the PBuffer's
// pixel data into the ColorBufferGl. The latter can then be displayed
// in the client's UI sub-window with ColorBufferGl::post().
//
// - Guest EGLImages are implemented as native gralloc buffers too.
// The guest glEGLImageTargetTexture2DOES() implementations will end up
// calling ColorBufferGl::bindToTexture() to bind the current context's
// GL_TEXTURE_2D to the buffer. Similarly, the guest versions of
// glEGLImageTargetRenderbufferStorageOES() will end up calling
// ColorBufferGl::bindToRenderbuffer().
//
// This forces the implementation to use a host EGLImage to implement each
// ColorBufferGl.
//
// As an additional twist.
namespace gfxstream {
namespace gl {
class TextureDraw;
class TextureResize;
class YUVConverter;
class ColorBufferGl {
public:
// Create a new ColorBufferGl instance.
// |display| is the host EGLDisplay handle.
// |width| and |height| are the buffer's dimensions in pixels.
// |internalFormat| is the internal OpenGL pixel format to use, valid
// values
// are: GL_RGB, GL_RGB565, GL_RGBA, GL_RGB5_A1_OES and GL_RGBA4_OES.
// Implementation is free to use something else though.
// |frameworkFormat| specifies the original format of the guest
// color buffer so that we know how to convert to |internalFormat|,
// if necessary (otherwise, frameworkFormat ==
// FRAMEWORK_FORMAT_GL_COMPATIBLE).
// It is assumed underlying EGL has EGL_KHR_gl_texture_2D_image.
// Returns NULL on failure.
// |fastBlitSupported|: whether or not this ColorBufferGl can be
// blitted and posted to swapchain without context switches.
static std::unique_ptr<ColorBufferGl> create(EGLDisplay display, int width, int height,
GLint internalFormat,
FrameworkFormat frameworkFormat, HandleType handle,
ContextHelper* helper, TextureDraw* textureDraw,
bool fastBlitSupported);
// Sometimes things happen and we need to reformat the GL texture
// used. This function replaces the format of the underlying texture
// with the internalformat specified.
void reformat(GLint internalformat, GLenum type);
// Destructor.
~ColorBufferGl();
// Return ColorBufferGl width and height in pixels
GLuint getWidth() const { return m_width; }
GLuint getHeight() const { return m_height; }
GLint getInternalFormat() const { return m_internalFormat; }
// Read the ColorBufferGl instance's pixel values into host memory.
void readPixels(int x,
int y,
int width,
int height,
GLenum p_format,
GLenum p_type,
void* pixels);
// Read the ColorBuffer instance's pixel values by first scaling
// to the size of width x height, then clipping a |rect| from the
// screen defined by width x height.
void readPixelsScaled(int width, int height, GLenum p_format, GLenum p_type, int skinRotation,
Rect rect, void* pixels);
// Read cached YUV pixel values into host memory.
void readPixelsYUVCached(int x,
int y,
int width,
int height,
void* pixels,
uint32_t pixels_size);
void swapYUVTextures(FrameworkFormat texture_type, GLuint* textures);
// Update the ColorBufferGl instance's pixel values from host memory.
// |p_format / p_type| are the desired OpenGL color buffer format
// and data type.
// Otherwise, subUpdate() will explicitly convert |pixels|
// to be in |p_format|.
bool subUpdate(int x, int y, int width, int height, GLenum p_format, GLenum p_type,
const void* pixels);
bool subUpdateFromFrameworkFormat(int x, int y, int width, int height,
FrameworkFormat fwkFormat, GLenum p_format, GLenum p_type,
const void* pixels);
// Completely replaces contents, assuming that |pixels| is a buffer
// that is allocated and filled with the same format.
bool replaceContents(const void* pixels, size_t numBytes);
// Reads back entire contents, tightly packed rows.
// If the framework format is YUV, it will read back as raw YUV data.
bool readContents(size_t* numBytes, void* pixels);
// Draw a ColorBufferGl instance, i.e. blit it to the current guest
// framebuffer object / window surface. This doesn't display anything.
bool draw();
// Returns the texture name of a texture containing the contents of this
// ColorBuffer but that is scaled to match the current viewport. This
// ColorBuffer retains ownership of the returned texture.
GLuint getViewportScaledTexture();
// Post this ColorBuffer to the host native sub-window.
// |rotation| is the rotation angle in degrees, clockwise in the GL
// coordinate space.
bool post(GLuint tex, float rotation, float dx, float dy);
// Post this ColorBufferGl to the host native sub-window and apply
// the device screen overlay (if there is one).
// |rotation| is the rotation angle in degrees, clockwise in the GL
// coordinate space.
bool postViewportScaledWithOverlay(float rotation, float dx, float dy);
// Bind the current context's EGL_TEXTURE_2D texture to this ColorBufferGl's
// EGLImage. This is intended to implement glEGLImageTargetTexture2DOES()
// for all GLES versions.
bool bindToTexture();
bool bindToTexture2();
// Bind the current context's EGL_RENDERBUFFER_OES render buffer to this
// ColorBufferGl's EGLImage. This is intended to implement
// glEGLImageTargetRenderbufferStorageOES() for all GLES versions.
bool bindToRenderbuffer();
// Copy the content of the current context's read surface to this
// ColorBufferGl. This is used from WindowSurface::flushColorBuffer().
// Return true on success, false on failure (e.g. no current context).
bool blitFromCurrentReadBuffer();
// Read the content of the whole ColorBufferGl as 32-bit RGBA pixels.
// |img| must be a buffer large enough (i.e. width * height * 4).
void readback(unsigned char* img, bool readbackBgra = false);
// readback() but async (to the specified |buffer|)
void readbackAsync(GLuint buffer, bool readbackBgra = false);
void onSave(android::base::Stream* stream);
static std::unique_ptr<ColorBufferGl> onLoad(android::base::Stream* stream,
EGLDisplay p_display, ContextHelper* helper,
TextureDraw* textureDraw, bool fastBlitSupported);
HandleType getHndl() const;
bool isFastBlitSupported() const { return m_fastBlitSupported; }
void postLayer(const ComposeLayer& l, int frameWidth, int frameHeight);
GLuint getTexture();
std::unique_ptr<BorrowedImageInfo> getBorrowedImageInfo();
// ColorBufferGl backing change methods
//
// Change to opaque fd or opaque win32 handle-backed VkDeviceMemory
// via GL_EXT_memory_objects
bool importMemory(android::base::ManagedDescriptor externalDescriptor, uint64_t size,
bool dedicated, bool linearTiling);
// Change to EGL native pixmap
bool importEglNativePixmap(void* pixmap, bool preserveContent);
// Change to some other native EGL image. nativeEglImage must not have
// been created from our s_egl.eglCreateImage.
bool importEglImage(void* nativeEglImage, bool preserveContent);
void setSync(bool debug = false);
void waitSync(bool debug = false);
void setDisplay(uint32_t displayId) { m_displayId = displayId; }
uint32_t getDisplay() { return m_displayId; }
FrameworkFormat getFrameworkFormat() { return m_frameworkFormat; }
public:
void restore();
private:
ColorBufferGl(EGLDisplay display, HandleType hndl, GLuint width, GLuint height,
ContextHelper* helper, TextureDraw* textureDraw);
// Helper function to get contents.
std::vector<uint8_t> getContents();
// Helper function to clear current EGL image.
void clearStorage();
// Helper function to bind EGL image as texture. Assumes storage cleared.
void restoreEglImage(EGLImageKHR image);
// Helper function that does the above two operations in one go.
void rebindEglImage(EGLImageKHR image, bool preserveContent);
private:
GLuint m_tex = 0;
GLuint m_blitTex = 0;
EGLImageKHR m_eglImage = nullptr;
EGLImageKHR m_blitEGLImage = nullptr;
const GLuint m_width = 0;
const GLuint m_height = 0;
GLuint m_fbo = 0;
GLint m_internalFormat = 0;
GLint m_sizedInternalFormat = 0;
// This is helpful for bindFbo which may skip too many steps after the egl
// image is replaced.
bool m_needFboReattach = false;
// |m_format| and |m_type| are for reformatting purposes only
// to work around bugs in the guest. No need to snapshot those.
bool m_needFormatCheck = true;
GLenum m_format = 0; // TODO: Currently we treat m_internalFormat same as
// m_format, but if underlying drivers can take it,
// it may be a better idea to distinguish them, with
// m_internalFormat as an explicitly sized format; then
// guest can specify everything in terms of explicitly
// sized internal formats and things will get less
// ambiguous.
GLenum m_type = 0;
EGLDisplay m_display = nullptr;
ContextHelper* m_helper = nullptr;
TextureDraw* m_textureDraw = nullptr;
TextureResize* m_resizer = nullptr;
FrameworkFormat m_frameworkFormat;
GLuint m_yuv_conversion_fbo = 0; // FBO to offscreen-convert YUV to RGB
GLuint m_scaleRotationFbo = 0; // FBO to read scaled rotation pixels
std::unique_ptr<YUVConverter> m_yuv_converter;
HandleType mHndl;
GLsync m_sync = nullptr;
bool m_fastBlitSupported = false;
bool m_vulkanOnly = false;
GLenum m_asyncReadbackType = GL_UNSIGNED_BYTE;
size_t m_numBytes = 0;
bool m_importedMemory = false;
GLuint m_memoryObject = 0;
bool m_inUse = false;
bool m_isBuffer = false;
GLuint m_buf = 0;
uint32_t m_displayId = 0;
bool m_BRSwizzle = false;
};
typedef std::shared_ptr<ColorBufferGl> ColorBufferGlPtr;
} // namespace gl
} // namespace gfxstream